forked from rcore-os/zCore
Compare commits
No commits in common. "master" and "gh-pages" have entirely different histories.
|
|
@ -1,16 +0,0 @@
|
|||
[alias]
|
||||
xtask = "run --package xtask --release --"
|
||||
git-proxy = "xtask git-proxy"
|
||||
setup = "xtask setup"
|
||||
update-all = "xtask update-all"
|
||||
|
||||
check-style = "xtask check-style"
|
||||
|
||||
rootfs = "xtask rootfs"
|
||||
libc-test = "xtask libc-test"
|
||||
other-test = "xtask other-test"
|
||||
image = "xtask image"
|
||||
|
||||
asm = "xtask asm"
|
||||
qemu = "xtask qemu"
|
||||
gdb = "xtask gdb"
|
||||
|
|
@ -1 +0,0 @@
|
|||
prebuilt/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y $@
|
||||
pip3 install -r tests/requirements.txt
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
wget https://download.qemu.org/qemu-$1.tar.xz
|
||||
tar -xJf qemu-$1.tar.xz
|
||||
cd qemu-$1
|
||||
./configure --target-list=x86_64-softmmu,riscv64-softmmu
|
||||
make -j$nproc > /dev/null 2>&1
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
name: Build CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 22 * * *' # every day at 22:00 UTC
|
||||
|
||||
env:
|
||||
rust_toolchain: nightly-2022-01-20
|
||||
|
||||
jobs:
|
||||
workspace:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
override: true
|
||||
components: rust-src, rustfmt, clippy
|
||||
|
||||
- name: Check format
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --all-features
|
||||
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --all-features
|
||||
|
||||
- name: Build docs
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: doc
|
||||
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: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
mode: [linux, zircon]
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, clippy
|
||||
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --package zcore --features "${{ matrix.mode }} libos"
|
||||
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --package zcore --features "${{ matrix.mode }} libos"
|
||||
|
||||
test-bare-metal:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x86_64, riscv64]
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, clippy
|
||||
|
||||
- uses: actions-rs/install@v0.1
|
||||
with:
|
||||
crate: cargo-binutils
|
||||
version: latest
|
||||
|
||||
- name: Build ${{ matrix.arch }} bare-metal zircon
|
||||
if: matrix.arch == 'x86_64'
|
||||
run: cd zCore && make build ARCH=${{ matrix.arch }}
|
||||
|
||||
- name: Clippy ${{ matrix.arch }} bare-metal zircon
|
||||
if: matrix.arch == 'x86_64'
|
||||
run: cd zCore && make clippy ARCH=${{ matrix.arch }}
|
||||
|
||||
- name: Build ${{ matrix.arch }} bare-metal linux
|
||||
if: matrix.arch == 'riscv64'
|
||||
run: cd zCore && make build ARCH=${{ matrix.arch }} LINUX=1
|
||||
|
||||
- name: Clippy ${{ matrix.arch }} bare-metal linux
|
||||
if: matrix.arch == 'riscv64'
|
||||
run: cd zCore && make clippy ARCH=${{ matrix.arch }} LINUX=1
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
name: Deploy docs
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
rust_toolchain: nightly-2022-01-20
|
||||
|
||||
jobs:
|
||||
doc:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
|
||||
- name: Build docs
|
||||
run: |
|
||||
cargo doc --no-deps --all-features
|
||||
.github/scripts/add-doc-index.sh
|
||||
|
||||
- name: Deploy to Github Pages
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
uses: JamesIves/github-pages-deploy-action@releases/v3
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: target/doc
|
||||
|
|
@ -1,281 +0,0 @@
|
|||
name: Test CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 22 * * *' # every day at 22:00 UTC
|
||||
|
||||
env:
|
||||
rust_toolchain: nightly-2022-01-20
|
||||
qemu_version: 7.0.0
|
||||
|
||||
jobs:
|
||||
unit-test:
|
||||
name: Unit Test
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
|
||||
- name: Run unit test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --no-fail-fast
|
||||
env:
|
||||
CARGO_INCREMENTAL: '0'
|
||||
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
|
||||
RUSTDOCFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
|
||||
|
||||
- name: Cache grcov
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-grcov
|
||||
|
||||
- name: Gather coverage data
|
||||
id: coverage
|
||||
uses: actions-rs/grcov@v0.1
|
||||
# FIXME: 'error from lcovParse: Failed to parse string'
|
||||
# - name: Coveralls upload
|
||||
# uses: coverallsapp/github-action@master
|
||||
# with:
|
||||
# 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-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
|
||||
- name: Pull prebuilt images
|
||||
run: |
|
||||
git lfs pull -I prebuilt/zircon/x64/core-tests.zbi
|
||||
git lfs pull -I prebuilt/zircon/x64/libzircon-libos.so
|
||||
git lfs pull -I prebuilt/zircon/x64/userboot-libos.so
|
||||
|
||||
- name: Install python dependencies
|
||||
run: .github/scripts/install-deps.sh
|
||||
|
||||
- name: Run fast tests
|
||||
if: github.event_name != 'schedule'
|
||||
run: cd tests && python3 zircon_core_test.py --libos --fast --no-failed
|
||||
|
||||
- name: Run full tests
|
||||
if: github.event_name == 'schedule'
|
||||
run: cd tests && python3 zircon_core_test.py --libos
|
||||
|
||||
linux-libc-test-libos:
|
||||
name: Linux Libc Test Libos
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
|
||||
- name: Install dependencies
|
||||
run: .github/scripts/install-deps.sh musl-tools musl-dev
|
||||
|
||||
- name: Prepare rootfs
|
||||
run: make libc-test
|
||||
|
||||
- name: Run fast tests
|
||||
if: github.event_name != 'schedule'
|
||||
run: cd tests && python3 linux_libc_test.py --libos --fast
|
||||
|
||||
- name: Run full tests
|
||||
if: github.event_name == 'schedule'
|
||||
run: cd tests && python3 linux_libc_test.py --libos
|
||||
|
||||
zircon-core-test-baremetal:
|
||||
name: Zircon Core Test Baremetal
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
|
||||
- name: 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 }}-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-x86_64 --version
|
||||
|
||||
- name: Run fast tests
|
||||
if: github.event_name != 'schedule'
|
||||
run: cd tests && python3 zircon_core_test.py --fast
|
||||
|
||||
- name: Run full tests
|
||||
if: github.event_name == 'schedule'
|
||||
run: cd tests && python3 zircon_core_test.py
|
||||
|
||||
linux-libc-test-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
|
||||
with:
|
||||
crate: cargo-binutils
|
||||
version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: .github/scripts/install-deps.sh musl-tools musl-dev ninja-build
|
||||
|
||||
- name: Cache QEMU
|
||||
id: cache-qemu
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: qemu-${{ env.qemu_version }}
|
||||
key: qemu-${{ env.qemu_version }}-x86_64-riscv64
|
||||
|
||||
- name: Download and Compile QEMU
|
||||
if: steps.cache-qemu.outputs.cache-hit != 'true'
|
||||
run: .github/scripts/install-qemu.sh ${{ env.qemu_version }}
|
||||
|
||||
- name: Install QEMU
|
||||
run: |
|
||||
cd qemu-${{ env.qemu_version }} && sudo make install
|
||||
qemu-system-${{ matrix.arch }} --version
|
||||
|
||||
- name: Prepare rootfs
|
||||
run: make libc-test ARCH=${{ matrix.arch }} && make image ARCH=${{ matrix.arch }}
|
||||
|
||||
- name: Run fast tests
|
||||
if: github.event_name != 'schedule'
|
||||
run: cd tests && python3 linux_libc_test.py --arch ${{ matrix.arch }} --fast
|
||||
|
||||
- name: Run full tests
|
||||
if: github.event_name == 'schedule'
|
||||
run: cd tests && python3 linux_libc_test.py --arch ${{ matrix.arch }}
|
||||
|
||||
linux-other-test-baremetal:
|
||||
name: Linux Other Test Baremetal
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x86_64, riscv64]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
|
||||
- if: matrix.arch == 'riscv64'
|
||||
uses: actions-rs/install@v0.1
|
||||
with:
|
||||
crate: cargo-binutils
|
||||
version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: .github/scripts/install-deps.sh musl-tools musl-dev ninja-build
|
||||
|
||||
- name: Cache QEMU
|
||||
id: cache-qemu
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: qemu-${{ env.qemu_version }}
|
||||
key: qemu-${{ env.qemu_version }}-x86_64-riscv64
|
||||
|
||||
- name: Download and Compile QEMU
|
||||
if: steps.cache-qemu.outputs.cache-hit != 'true'
|
||||
run: .github/scripts/install-qemu.sh ${{ env.qemu_version }}
|
||||
|
||||
- name: Install QEMU
|
||||
run: |
|
||||
cd qemu-${{ env.qemu_version }} && sudo make install
|
||||
qemu-system-${{ matrix.arch }} --version
|
||||
|
||||
- name: Prepare rootfs
|
||||
run: make other-test ARCH=${{ matrix.arch }} && make image ARCH=${{ matrix.arch }}
|
||||
|
||||
- name: Run fast tests
|
||||
if: github.event_name != 'schedule'
|
||||
run: cd tests && python3 linux_other_test.py --arch ${{ matrix.arch }} --fast
|
||||
|
||||
- name: Run full tests
|
||||
if: github.event_name == 'schedule'
|
||||
run: cd tests && python3 linux_other_test.py --arch ${{ matrix.arch }}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
**/.*
|
||||
!.github/
|
||||
!.cargo/
|
||||
!.vscode/settings.json
|
||||
|
||||
**/target
|
||||
**/*.rs.bk
|
||||
*.img
|
||||
*.bin
|
||||
*.log
|
||||
Cargo.lock
|
||||
|
||||
/ignored
|
||||
/rootfs
|
||||
zCore/src/platform/riscv/kernel-vars.ld
|
||||
|
||||
.DS_Store
|
||||
__pycache__
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
[submodule "rboot"]
|
||||
path = rboot
|
||||
url = https://github.com/rcore-os/rboot.git
|
||||
[submodule "tests"]
|
||||
path = tests
|
||||
url = https://github.com/rcore-os/zcore-tests.git
|
||||
[submodule "libc-test"]
|
||||
path = libc-test
|
||||
url = https://github.com/rcore-os/libc-test
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
// Prevent "can't find crate for `test`" error on no_std
|
||||
// Ref: https://github.com/rust-lang/vscode-rust/issues/729
|
||||
// For vscode-rust plugin users:
|
||||
"rust.target": "riscv64imac-unknown-none-elf",
|
||||
"rust.all_targets": false,
|
||||
// For Rust Analyzer plugin users:
|
||||
"rust-analyzer.cargo.target": "riscv64imac-unknown-none-elf",
|
||||
"rust-analyzer.checkOnSave.enable": false
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
These documentation pages include resources by third parties. This copyright
|
||||
file applies only to those resources. The following third party resources are
|
||||
included, and carry their own copyright notices and license terms:
|
||||
|
||||
* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2,
|
||||
FiraSans-Regular.woff, FiraSans-Medium.woff):
|
||||
|
||||
Copyright (c) 2014, Mozilla Foundation https://mozilla.org/
|
||||
with Reserved Font Name Fira Sans.
|
||||
|
||||
Copyright (c) 2014, Telefonica S.A.
|
||||
|
||||
Licensed under the SIL Open Font License, Version 1.1.
|
||||
See FiraSans-LICENSE.txt.
|
||||
|
||||
* rustdoc.css, main.js, and playpen.js:
|
||||
|
||||
Copyright 2015 The Rust Developers.
|
||||
Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or
|
||||
the MIT license (LICENSE-MIT.txt) at your option.
|
||||
|
||||
* normalize.css:
|
||||
|
||||
Copyright (c) Nicolas Gallagher and Jonathan Neal.
|
||||
Licensed under the MIT license (see LICENSE-MIT.txt).
|
||||
|
||||
* Source Code Pro (SourceCodePro-Regular.ttf.woff2,
|
||||
SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2,
|
||||
SourceCodePro-Regular.ttf.woff, SourceCodePro-Semibold.ttf.woff,
|
||||
SourceCodePro-It.ttf.woff):
|
||||
|
||||
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/),
|
||||
with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark
|
||||
of Adobe Systems Incorporated in the United States and/or other countries.
|
||||
|
||||
Licensed under the SIL Open Font License, Version 1.1.
|
||||
See SourceCodePro-LICENSE.txt.
|
||||
|
||||
* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2,
|
||||
SourceSerif4-It.ttf.woff2, SourceSerif4-Regular.ttf.woff,
|
||||
SourceSerif4-Bold.ttf.woff, SourceSerif4-It.ttf.woff):
|
||||
|
||||
Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name
|
||||
'Source'. All Rights Reserved. Source is a trademark of Adobe in the United
|
||||
States and/or other countries.
|
||||
|
||||
Licensed under the SIL Open Font License, Version 1.1.
|
||||
See SourceSerif4-LICENSE.md.
|
||||
|
||||
This copyright file is intended to be distributed with rustdoc output.
|
||||
17
Cargo.toml
17
Cargo.toml
|
|
@ -1,17 +0,0 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"drivers",
|
||||
"kernel-hal",
|
||||
"zircon-object",
|
||||
"zircon-syscall",
|
||||
"linux-object",
|
||||
"linux-syscall",
|
||||
"loader",
|
||||
"zCore",
|
||||
"xtask",
|
||||
]
|
||||
default-members = ["xtask"]
|
||||
exclude = ["zircon-user", "rboot"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
|
||||
with Reserved Font Name < Fira >,
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
21
LICENSE
21
LICENSE
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019-2020 rCore Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
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.
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, 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.
|
||||
53
Makefile
53
Makefile
|
|
@ -1,53 +0,0 @@
|
|||
# Makefile for top level of zCore
|
||||
|
||||
ARCH ?= x86_64
|
||||
|
||||
.PHONY: help setup update rootfs libc-test other-test image check doc clean
|
||||
|
||||
# print top level help
|
||||
help:
|
||||
cargo xtask help
|
||||
|
||||
# setup git lfs and git submodules
|
||||
setup:
|
||||
cargo setup
|
||||
|
||||
# update toolchain and dependencies
|
||||
update:
|
||||
cargo update-all
|
||||
|
||||
# put rootfs for linux mode
|
||||
rootfs:
|
||||
cargo rootfs --arch $(ARCH)
|
||||
|
||||
# put libc tests into rootfs
|
||||
libc-test:
|
||||
cargo libc-test --arch $(ARCH)
|
||||
|
||||
# put other tests into rootfs
|
||||
other-test:
|
||||
cargo other-test --arch $(ARCH)
|
||||
|
||||
# build image from rootfs
|
||||
image:
|
||||
cargo image --arch $(ARCH)
|
||||
|
||||
# check code style
|
||||
check:
|
||||
cargo check-style
|
||||
|
||||
# build and open project document
|
||||
doc:
|
||||
cargo doc --open
|
||||
|
||||
# clean targets
|
||||
clean:
|
||||
cargo clean
|
||||
rm -rf rootfs
|
||||
rm -rf ignored/target
|
||||
find zCore -maxdepth 1 -name "*.img" -delete
|
||||
|
||||
rt-test:
|
||||
cd rootfs/x86_64 && git clone https://kernel.googlesource.com/pub/scm/linux/kernel/git/clrkwllms/rt-tests --depth 1
|
||||
cd rootfs/x86_64/rt-tests && make
|
||||
echo x86 gcc build rt-test,now need manual modificy.
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/),
|
||||
|
||||
with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic,
|
||||
NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen,
|
||||
Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco,
|
||||
NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic,
|
||||
Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
282
README.md
282
README.md
|
|
@ -1,282 +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!
|
||||
|
||||
## Manual
|
||||
|
||||
[This](docs/Manual.md) is a new simple chinese manual.
|
||||
|
||||
## 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)
|
||||
- [Git LFS](https://git-lfs.github.com)
|
||||
|
||||
### 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
|
||||
git lfs install
|
||||
git lfs pull
|
||||
```
|
||||
|
||||
For users in China, there's a mirror you can try:
|
||||
|
||||
```sh
|
||||
git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
|
||||
```
|
||||
|
||||
### Run zcore in libos mode
|
||||
|
||||
#### Run zcore in linux-libos mode
|
||||
|
||||
- step 1: Prepare Alpine Linux rootfs:
|
||||
|
||||
```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>
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,93 @@
|
|||
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,93 @@
|
|||
Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="1792" height="1792" viewBox="0 0 1792 1792"><path d="M1615 0q70 0 122.5 46.5t52.5 116.5q0 63-45 151-332 629-465 752-97 91-218 91-126 0-216.5-92.5t-90.5-219.5q0-128 92-212l638-579q59-54 130-54zm-909 1034q39 76 106.5 130t150.5 76l1 71q4 213-129.5 347t-348.5 134q-123 0-218-46.5t-152.5-127.5-86.5-183-29-220q7 5 41 30t62 44.5 59 36.5 46 17q41 0 55-37 25-66 57.5-112.5t69.5-76 88-47.5 103-25.5 125-10.5z"/></svg>
|
||||
|
After Width: | Height: | Size: 455 B |
|
|
@ -0,0 +1 @@
|
|||
<svg width="24" height="25" viewBox="0 0 24 25" xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard"><path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/><path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/></svg>
|
||||
|
After Width: | Height: | Size: 576 B |
|
|
@ -1,86 +0,0 @@
|
|||
# zCore 项目使用指南
|
||||
|
||||
## 预定功能
|
||||
|
||||
预定功能指的是 zCore 作为一个项目,为开发者和用户常用操作提供的封装。
|
||||
|
||||
由于历史原因,目前预定功能分为顶层预定功能和内核预定功能。
|
||||
所有顶层提供的预定功能都定义于 [顶层 Makefile](../Makefile),
|
||||
并且所有预定功能最终都将移动到顶层。
|
||||
|
||||
## 常规操作流程
|
||||
|
||||
对于一般开发者和用户,可以按以下步骤设置 zCore 项目。
|
||||
|
||||
1. 先决条件
|
||||
|
||||
目前已测试的开发环境包括 Ubuntu20.04、Ubuntu22.04 和 Debian11,
|
||||
Ubuntu22.04 不能正确编译 x86_64 的 libc 测试。
|
||||
若不需要烧写到物理硬件,使用 WSL2 或其他虚拟机的操作与真机并无不同之处。
|
||||
|
||||
在开始之前,确保你的计算机上安装了 git 和 rustup。要在虚拟环境开发或测试,需要 QEMU。
|
||||
|
||||
2. 克隆项目
|
||||
|
||||
```bash
|
||||
git clone https://github.com/rcore-os/zCore.git
|
||||
```
|
||||
|
||||
3. 初始化存储库
|
||||
|
||||
```bash
|
||||
make setup
|
||||
```
|
||||
|
||||
4. 保持更新
|
||||
|
||||
```bash
|
||||
make update
|
||||
```
|
||||
|
||||
5. 探索更多操作
|
||||
|
||||
```bash
|
||||
make help
|
||||
```
|
||||
|
||||
6. 推到仓库前,现在本机执行测试
|
||||
|
||||
```bash
|
||||
make check # CI/build 的一部分,未来会实现更多快速测试指令
|
||||
```
|
||||
|
||||
## Linux 模式
|
||||
|
||||
zCore 根据向用户提供的系统调用的不同,可分为 zircon 模式和 linux 模式。
|
||||
要以 linux 模式启动,需要先构建 linux 的启动文件系统。
|
||||
|
||||
这个指令构建适于 x86_64 架构的启动文件系统。
|
||||
|
||||
```bash
|
||||
make rootfs ARCH=x86_64
|
||||
```
|
||||
|
||||
这个指令构建适于 riscv64 架构的启动文件系统。
|
||||
|
||||
```bash
|
||||
make rootfs ARCH=riscv64
|
||||
```
|
||||
|
||||
要执行 musl-libc 测试集,需要向文件系统中添加 libc 测试集:
|
||||
|
||||
```bash
|
||||
make libc-test <ARCH=?>
|
||||
```
|
||||
|
||||
要执行 CI 的其他测试,需要向文件系统中添加相应测试集:
|
||||
|
||||
```bash
|
||||
make other-test <ARCH=?>
|
||||
```
|
||||
|
||||
要以裸机模式启动 zCore,需要构造将放到设备或虚拟环境中的镜像文件:
|
||||
|
||||
```bash
|
||||
make image <ARCH=?>
|
||||
```
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
# zCore for riscv64
|
||||
|
||||
## 编译 zCore 系统镜像
|
||||
|
||||
先在源码根目录下编译 riscv64 的文件系统。
|
||||
|
||||
然后进入子目录 zCore 编译内核,会生成系统镜像`zcore.bin`
|
||||
|
||||
```sh
|
||||
make riscv-image
|
||||
cd zCore
|
||||
make build LINUX=1 ARCH=riscv64 PLATFORM=d1 MODE=release
|
||||
```
|
||||
|
||||
## riscv64 开发板的烧写
|
||||
|
||||
以全志 D1 c906 开发板为例。
|
||||
|
||||
下载并编译烧写工具 `xfel`:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/xboot/xfel.git
|
||||
cd xfel
|
||||
make
|
||||
```
|
||||
|
||||
### 自动烧写运行:
|
||||
|
||||
安装好工具 `xfel`,开发板进入 FEL 模式,可在开发板的 Linux 系统中执行 `reboot efex` 命令进入 FEL 模式。然后运行:
|
||||
|
||||
```sh
|
||||
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:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/elliott10/opensbi -b thead
|
||||
cd opensbi
|
||||
make PLATFORM=thead/c910 CROSS_COMPILE=/path/to/toolchain/bin/riscv64-unknown-linux-gnu- SUNXI_CHIP=sun20iw1p1 PLATFORM_RISCV_ISA=rv64gcxthead
|
||||
```
|
||||
|
||||
或使用预编译的镜像 [prebuilt/firmware/d1/fw_payload.elf](../prebuilt/firmware/d1/fw_payload.elf)。
|
||||
|
||||
2. 生成包含了 OpenSBI, dtb, zCore 的待烧写固件:
|
||||
|
||||
```sh
|
||||
rust-objcopy --binary-architecture=riscv64 ../prebuilt/firmware/d1/fw_payload.elf --strip-all -O binary ./zcore_d1.bin
|
||||
dd if=../target/riscv64/release/zcore.bin of=zcore_d1.bin bs=512 seek=2048
|
||||
```
|
||||
|
||||
3. 启动全志 D1 c906 开发板,并进入 FEL 模式。然后通过烧写工具 `xfel` 把 zCore 系统镜像载入到 DDR 中:
|
||||
|
||||
```
|
||||
sudo xfel ddr ddr3
|
||||
sudo xfel write 0x40000000 zcore_d1.bin
|
||||
sudo xfel exec 0x40000000
|
||||
```
|
||||
|
||||
## 引导运行
|
||||
|
||||
zCore 成功引导后, OpenSBI 会将 dtb 加载到高地址 `0x5ff00000`,运行如下所示:
|
||||
|
||||
```
|
||||
OpenSBI smartx-d1-tina-v1.0.1-release
|
||||
____ _____ ____ _____
|
||||
/ __ \ / ____| _ \_ _|
|
||||
| | | |_ __ ___ _ __ | (___ | |_) || |
|
||||
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
|
||||
| |__| | |_) | __/ | | |____) | |_) || |_
|
||||
\____/| .__/ \___|_| |_|_____/|____/_____|
|
||||
| |
|
||||
|_|
|
||||
|
||||
Platform Name : T-HEAD Xuantie Platform
|
||||
Platform HART Features : RV64ACDFIMSUVX
|
||||
Platform Max HARTs : 1
|
||||
Current Hart : 0
|
||||
Firmware Base : 0x40000400
|
||||
Firmware Size : 75 KB
|
||||
Runtime SBI Version : 0.2
|
||||
|
||||
MIDELEG : 0x0000000000000222
|
||||
MEDELEG : 0x000000000000b1ff
|
||||
PMP0 : 0x0000000040000000-0x000000004001ffff (A)
|
||||
PMP1 : 0x0000000040000000-0x000000007fffffff (A,R,W,X)
|
||||
PMP2 : 0x0000000080000000-0x00000000bfffffff (A,R,W,X)
|
||||
PMP3 : 0x0000000000020000-0x0000000000027fff (A,R,W,X)
|
||||
PMP4 : 0x0000000000000000-0x000000003fffffff (A,R,W)
|
||||
____
|
||||
____/ ___|___ _ __ ___
|
||||
|_ / | / _ \| '__/ _ \
|
||||
/ /| |__| (_) | | | __/
|
||||
/___|\____\___/|_| \___|
|
||||
|
||||
Welcome to zCore rust_main( hartid: 0x0, device_tree_paddr: 0x44ddc )
|
||||
Uart output testing
|
||||
+++ Setting up UART interrupts +++
|
||||
+++ Setting up PLIC +++
|
||||
+++ setup interrupt +++
|
||||
Exception::Breakpoint: A breakpoint set @0xffffffffc0167f56
|
||||
Device Tree @ 0x0
|
||||
[138.8430296s WARN 0 0:0] elf relocate Err:".rela.dyn not found"
|
||||
[139.2137079s WARN 0 0:0] brk: unimplemented
|
||||
[139.8335662s WARN 0 0:0] TCGETS | TIOCGWINSZ | TIOCSPGRP, pretend to be tty.
|
||||
[140.5358217s WARN 0 0:0] TIOCGPGRP, pretend to be have a tty process group.
|
||||
[140.6017734s WARN 0 0:0] getpgid: unimplemented
|
||||
[140.8971624s WARN 0 0:0] setpgid: unimplemented
|
||||
/ #
|
||||
/ # ls
|
||||
bin dev tmp
|
||||
/ # hello
|
||||
Hello world from user mode program!
|
||||
By xiaoluoyuan@163.com
|
||||
/ #
|
||||
|
||||
```
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
# Porting zCore to RiscV64 (Qemu)
|
||||
|
||||
### 2021-03-04
|
||||
<br>之前的内存部分,使用的比较简单的页表映射大页的方式;
|
||||
<br>在加载Qemu文件系统镜像到内存中解开时使用,就需要对虚拟内存、virtio-blk-device以及SimpleFileSystem完全初始化好;
|
||||
<br>其中有些可以比较方便地调用crate库;
|
||||
<br>对中间抽象层kernel-hal的内存操作相关函数的实现:
|
||||
* PageTable 新建页表或获取页表;
|
||||
* trait PageTableTrait,从虚拟地址到物理地址的映射、查询等;
|
||||
* hal_frame_alloc物理帧实现;
|
||||
* pmem_write/read物理地址访问;
|
||||
|
||||
<br>其中,把rCore中的可复用的页表构建PageTableImpl,实际映射的MemoryArea,移到zCore中;
|
||||
<br>在底下bare层的函数变量暴露给启动部分使用,修复一些错误;
|
||||
<br>从目前的运行结果看,应该是页表部分应该是切换好了;
|
||||
```
|
||||
[1.2317591s DEBUG 0 0:0] switch table 8000000000080220 -> 8000000000080a49
|
||||
```
|
||||
|
||||
### zCore系统结构<br>
|
||||

|
||||
|
||||
### riscv64初始移植路径<br>
|
||||
按照:<br>
|
||||
|Qemu riscv64|-|kernel-hal-bare|-|kernel-hal|-|zircon-object/ linux-object|-|linux-syscall|-|linux-loader|-|busybox|
|
||||
|-|-|-|-|-|-|-|-|-|-|-|-|-|
|
||||
|
||||
### 实现思路
|
||||
|
||||
* 分析Makefile的结构,弄清楚包括编译和运行的命令执行流;
|
||||
* 结合Qemu virt和opensbi以及编译出所需文件格式的kernel,也包括用户文件系统生成由x86_64到riscv64,这些命令过程写入Makefile;
|
||||
* 分析Cargo.toml的结构,理解各个features和依赖库crates的关系,如有些是可选的;
|
||||
<br><br>
|
||||
* 创建关于riscv64的Rust target-spec-json编译目标规格描述.json
|
||||
* 创建riscv64对应的链接脚本.ld以及启动入口汇编.asm
|
||||
* 重要的修改部分在kernel-hal-bare,arch下添加riscv架构,包括硬件初始化和对opensbi接口调用的封装;
|
||||
<br><br>
|
||||
|
||||
* 先定一个小目标,让OS跑起来打印初始一段字符
|
||||
* 这时会有大量的编译错误提示,需要解决,Rust错误提示很详细,会建议如何来修正:
|
||||
- 报错可能来自多个方面,包括:riscv64在Cargo.toml中的依赖库,非必需的crates先关掉,添加架构相关所需要的;
|
||||
- kernel-hal-bare中缺失的待实现的接口,可见kernel-hal中的定义;参考了arch/x86_64的函数;
|
||||
- 与target_arch由x86_64移植到riscv64的cfg,其相关的函数或变量需在代码中补上;
|
||||
- 变量及函数的作用范围等需要注意
|
||||
* Rust的条件编译cfg,`#[cfg(target_arch = "x86_64")]`也需要为riscv64实现一份;
|
||||
|
||||
* 要让OS能打印,要把串口输出初始化;
|
||||
- 有两种方式:一种是调用opensbi的打印接口,一种是MMIO的方式初始化串口输出;
|
||||
- 然后实现fmt::Write和宏println;
|
||||
<br><br>
|
||||
|
||||
|
||||
* 关于中断,可通过调用crate riscv,方便的进行指令和寄存器操作;
|
||||
* 陷入trap填入riscv64上下文切换的汇编;
|
||||
* 初始化S态各种中断,包括时钟中断和plic外部中断,在这里的Qemu和K210开发板会有不同;
|
||||
- K210对指令`rdtime`报错非法指令,且无法通过tval取得指令值,故K210无法通过riscv::register::time::read()读当前时间;Qemu无此问题;
|
||||
- 通过联合opensbi调试,riscv当硬件决定触发时钟中断时,会将sip寄存器的STIP位设置为1;当一条指令执行完毕后,如果发现STIP为1,此时如果sie 的STIE位也为1,会进入S态时钟中断的处理程序;
|
||||
- 当在M态不进行时钟中断委派到S态时,Qemu的M态可接收到S态时钟中断;
|
||||
- K210的M态无法收到S态中断,时钟中断和软件中断可以委派到S态来收, 而PLIC外部中断即使委派了也不行, 真是大坑! 同时也要感谢前面童鞋踩过坑的提示;
|
||||
|
||||
* PLIC外部中断是uart串口输出和virtio-blk-device加载文件系统的关键部分;
|
||||
- Qemu UART0_IRQ=10, K210的串口ID为33;
|
||||
- 通过MMIO地址对平台级中断控制器PLIC的寄存器进行设置:设置中断源的优先级,分0~7级,7是最高级;设置中断target的全局阀值[0..7], <= threshold会被屏蔽;
|
||||
- 使能target中某个给定ID的中断,中断ID可查找qemu/include/hw/riscv/virt.h;注意一个核的不同权限模式是不同Target,算出的Target不同则操作的地址也不同,跨步0x80;
|
||||
|
||||
|Target:| 0 | 1 | 2 | | 3 | 4 | 5 |
|
||||
|-|-|-|-|-|-|-|-|
|
||||
|Hart0:| M | S | U | Hart1:| M | S | U |
|
||||
|
||||
这里基于opensbi后一般运行于Hart0 S态,故为Target1
|
||||
|
||||
* PLIC中断初始化完成后,初始化串口中断,Qemu virt串口基地址是0x1000_0000,而K210是0x38000000;
|
||||
- 串口中断处理函数,在每个字符从键盘输入时,输出打印出来;
|
||||
|
||||
* 接着处理虚拟内存和文件系统
|
||||
|
||||
* 由Qemu启动opensbi,装载kernel并引导_start函数,初始化日志log打印,物理内存初始化,进入硬件初始化;
|
||||
* 后以slice的方式载入ramfs文件系统到内存指定地址,打开该SimpleFileSystem的文件系统并通过linux_loader调用用户程序busybox执行;
|
||||
|
||||
* 解析由rcore-fs-fuse生成的Simple FileSystem,通过SimpleFileSystem::open()来打开内存中的文件系统,读取文件和目录;
|
||||
* 最后通过linux_loader::run busybox sh
|
||||
|
||||
* 之前这部分工作由uefi bootloader的rboot把initramfs放到内存的指定地址;
|
||||
* 内存要初始化好,这里使用Qemu的virtio块设备,故也需要初始化好;
|
||||
|
||||
|
||||
移植未完...<br>
|
||||
系统运行效果演示:<br>
|
||||
|
||||
|
||||
在移植过程中,得到老师和童鞋们的很多帮助!感谢!
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 25 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg>
|
||||
|
After Width: | Height: | Size: 510 B |
|
|
@ -1,46 +0,0 @@
|
|||
[package]
|
||||
name = "zcore-drivers"
|
||||
version = "0.1.0"
|
||||
authors = ["Yuekai Jia <equation618@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = "Device drivers of zCore"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
graphic = ["rcore-console"]
|
||||
mock = ["async-std", "sdl2"]
|
||||
virtio = ["virtio-drivers"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
spin = "0.9"
|
||||
cfg-if = "1.0"
|
||||
bitflags = "1.3"
|
||||
lazy_static = "1.4"
|
||||
numeric-enum-macro = "0.2"
|
||||
device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "2f2e55f" }
|
||||
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "88e871a5" }
|
||||
pci = { git = "https://github.com/elliott10/pci-rs", rev = "8f33774b" }
|
||||
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "2aaf7d6", optional = true }
|
||||
rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "ca5b1bc", optional = true }
|
||||
lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "01b2e70" }
|
||||
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers", rev = "f7cd97a8", features = ["log"] }
|
||||
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "async"] }
|
||||
|
||||
# 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.8"
|
||||
|
|
@ -1,270 +0,0 @@
|
|||
// 解析设备树,创建已知的设备并为它们注册中断。
|
||||
//
|
||||
// 涉及到中断的设备包括:
|
||||
//
|
||||
// - 接收中断的中断控制器
|
||||
// - 发出中断的设备
|
||||
//
|
||||
// 有效的中断控制器应该具有下列三个属性:
|
||||
//
|
||||
// - `interrupt-controller`: 指示这是一个中断控制器
|
||||
// - `interrupt-cells`: 只是要向此控制器注册中断需要几个参数
|
||||
// - `phandle`: 向此控制器注册中断时使用的一个号码,如果没有设备需要向它注册,可能不存在
|
||||
//
|
||||
// 设备注册中断需要 `interrupts_extended` 属性,这是一个 `Vec<u32>`,形式为 `[{phandle, ...,}*]`,
|
||||
// 即控制器引用和控制器指定数量的参数。
|
||||
//! Probe devices and create drivers from device tree.
|
||||
//!
|
||||
//! Specification: <https://github.com/devicetree-org/devicetree-specification/releases/download/v0.3/devicetree-specification-v0.3.pdf>.
|
||||
|
||||
use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
|
||||
|
||||
use super::IoMapper;
|
||||
use crate::{
|
||||
utils::devicetree::{
|
||||
parse_interrupts, parse_reg, Devicetree, InheritProps, InterruptsProp, Node, StringList,
|
||||
},
|
||||
Device, DeviceError, DeviceResult, VirtAddr,
|
||||
};
|
||||
|
||||
const MODULE: &str = "device-tree";
|
||||
|
||||
type DevWithInterrupt = (Device, InterruptsProp);
|
||||
|
||||
/// 设备树中中断控制器特有的属性
|
||||
struct IntcProps {
|
||||
phandle: u32,
|
||||
interrupt_cells: u32,
|
||||
}
|
||||
|
||||
/// 查找表保存的中断控制器信息
|
||||
struct Intc {
|
||||
index: usize,
|
||||
cells: usize,
|
||||
}
|
||||
|
||||
/// A builder to probe devices and create drivers from device tree.
|
||||
pub struct DevicetreeDriverBuilder<M: IoMapper> {
|
||||
dt: Devicetree,
|
||||
io_mapper: M,
|
||||
}
|
||||
|
||||
impl<M: IoMapper> DevicetreeDriverBuilder<M> {
|
||||
/// Prepare to parse DTB from the given virtual address.
|
||||
pub fn new(dtb_base_vaddr: VirtAddr, io_mapper: M) -> DeviceResult<Self> {
|
||||
Ok(Self {
|
||||
dt: Devicetree::from(dtb_base_vaddr)?,
|
||||
io_mapper,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse the device tree from root, and returns an array of [`Device`] it found.
|
||||
pub fn build(&self) -> DeviceResult<Vec<Device>> {
|
||||
let mut intc_map = BTreeMap::new(); // phandle -> intc
|
||||
let mut dev_list = Vec::new(); // devices
|
||||
|
||||
// 解析设备树
|
||||
self.dt.walk(&mut |node, comp, props| {
|
||||
debug!(
|
||||
"{MODULE}: parsing node {:?} with compatible {comp:?}",
|
||||
node.name
|
||||
);
|
||||
// parse interrupt controller
|
||||
let res = if node.has_prop("interrupt-controller") {
|
||||
self.parse_intc(node, comp, props).map(|(dev, intc)| {
|
||||
intc_map.insert(
|
||||
intc.phandle,
|
||||
Intc {
|
||||
index: dev_list.len(),
|
||||
cells: intc.interrupt_cells as _,
|
||||
},
|
||||
);
|
||||
dev
|
||||
})
|
||||
} else {
|
||||
// parse other device
|
||||
match comp {
|
||||
#[cfg(feature = "virtio")]
|
||||
c if c.contains("virtio,mmio") => self.parse_virtio(node, props),
|
||||
c if c.contains("allwinner,sunxi-gmac") => {
|
||||
self.parse_ethernet(node, comp, props)
|
||||
}
|
||||
c if c.contains("ns16550a") || c.contains("allwinner,sun20i-uart") => {
|
||||
self.parse_uart(node, comp, props)
|
||||
}
|
||||
_ => Err(DeviceError::NotSupported),
|
||||
}
|
||||
};
|
||||
match res {
|
||||
Ok(dev) => dev_list.push(dev),
|
||||
Err(DeviceError::NotSupported) => {}
|
||||
Err(err) => warn!("{MODULE}: failed to parsing node {:?}: {err:?}", node.name),
|
||||
}
|
||||
});
|
||||
|
||||
// 注册中断
|
||||
for (device, interrupts_extended) in &dev_list {
|
||||
let mut extended = interrupts_extended.as_slice();
|
||||
// 分解 interrupts_extended
|
||||
while let [phandle, irq_num, ..] = extended {
|
||||
if let Some(Intc { index, cells }) = intc_map.get(phandle) {
|
||||
let (intc, _) = &dev_list[*index];
|
||||
extended = &extended[1 + cells..];
|
||||
if let Device::Irq(irq) = intc {
|
||||
if *irq_num != 0xffff_ffff {
|
||||
info!("{MODULE}: register interrupts for {intc:?}: {device:?}, irq_num={irq_num}");
|
||||
if irq.register_device(*irq_num as _, device.inner()).is_ok() {
|
||||
irq.unmask(*irq_num as _)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("{MODULE}: node with phandle {phandle:#x} is not an interrupt-controller");
|
||||
return Err(DeviceError::InvalidParam);
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"{MODULE}: no such node with phandle {phandle:#x} as the interrupt-parent"
|
||||
);
|
||||
return Err(DeviceError::InvalidParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 丢弃中断信息
|
||||
Ok(dev_list.into_iter().map(|(dev, _)| dev).collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[allow(unused_imports)]
|
||||
#[allow(unused_variables)]
|
||||
#[allow(unreachable_code)]
|
||||
impl<M: IoMapper> DevicetreeDriverBuilder<M> {
|
||||
/// Parse nodes for interrupt controllers.
|
||||
fn parse_intc(
|
||||
&self,
|
||||
node: &Node,
|
||||
comp: &StringList,
|
||||
props: &InheritProps,
|
||||
) -> DeviceResult<(DevWithInterrupt, IntcProps)> {
|
||||
let phandle = node
|
||||
.prop_u32("phandle")
|
||||
.map_err(|_| DeviceError::InvalidParam)?;
|
||||
let interrupt_cells = node
|
||||
.prop_u32("#interrupt-cells")
|
||||
.map_err(|_| DeviceError::InvalidParam)?;
|
||||
let interrupts_extended = parse_interrupts(node, props)?;
|
||||
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?)),
|
||||
_ => return Err(DeviceError::NotSupported),
|
||||
});
|
||||
|
||||
Ok((
|
||||
(dev, interrupts_extended),
|
||||
IntcProps {
|
||||
phandle,
|
||||
interrupt_cells,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
/// Parse nodes for virtio devices over MMIO.
|
||||
#[cfg(feature = "virtio")]
|
||||
fn parse_virtio(&self, node: &Node, props: &InheritProps) -> DeviceResult<DevWithInterrupt> {
|
||||
use crate::virtio::*;
|
||||
use virtio_drivers::{DeviceType, VirtIOHeader};
|
||||
|
||||
let interrupts_extended = parse_interrupts(node, props)?;
|
||||
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);
|
||||
}
|
||||
info!(
|
||||
"{MODULE}: detected virtio device: vendor_id={:#X}, type={:?}",
|
||||
header.vendor_id(),
|
||||
header.device_type()
|
||||
);
|
||||
|
||||
let dev = match header.device_type() {
|
||||
DeviceType::Block => Device::Block(Arc::new(VirtIoBlk::new(header)?)),
|
||||
DeviceType::GPU => Device::Display(Arc::new(VirtIoGpu::new(header)?)),
|
||||
DeviceType::Input => Device::Input(Arc::new(VirtIoInput::new(header)?)),
|
||||
DeviceType::Console => Device::Uart(Arc::new(VirtIoConsole::new(header)?)),
|
||||
_ => return Err(DeviceError::NotSupported),
|
||||
};
|
||||
|
||||
Ok((dev, interrupts_extended))
|
||||
}
|
||||
|
||||
/// Parse nodes for Ethernet devices.
|
||||
fn parse_ethernet(
|
||||
&self,
|
||||
node: &Node,
|
||||
comp: &StringList,
|
||||
props: &InheritProps,
|
||||
) -> DeviceResult<DevWithInterrupt> {
|
||||
let interrupts_extended = parse_interrupts(node, props)?;
|
||||
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];
|
||||
use crate::net::*;
|
||||
let dev = Device::Net(match comp {
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
c if c.contains("allwinner,sunxi-gmac") => {
|
||||
Arc::new(rtlx_init(irq_num as usize, |paddr, size| {
|
||||
self.io_mapper.query_or_map(paddr, size)
|
||||
})?)
|
||||
}
|
||||
_ => return Err(DeviceError::NotSupported),
|
||||
});
|
||||
|
||||
Ok((dev, interrupts_extended))
|
||||
}
|
||||
|
||||
/// Parse nodes for UART devices.
|
||||
fn parse_uart(
|
||||
&self,
|
||||
node: &Node,
|
||||
comp: &StringList,
|
||||
props: &InheritProps,
|
||||
) -> DeviceResult<DevWithInterrupt> {
|
||||
let interrupts_extended = parse_interrupts(node, props)?;
|
||||
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?) })
|
||||
}
|
||||
c if c.contains("allwinner,sun20i-uart") => {
|
||||
Arc::new(unsafe { Uart16550Mmio::<u32>::new(base_vaddr?) })
|
||||
}
|
||||
_ => return Err(DeviceError::NotSupported),
|
||||
});
|
||||
|
||||
Ok((dev, interrupts_extended))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
//! Various builders to probe devices and create corresponding drivers
|
||||
//! (e.g. device tree, ACPI table, ...)
|
||||
|
||||
mod devicetree;
|
||||
|
||||
pub use devicetree::DevicetreeDriverBuilder;
|
||||
|
||||
use crate::{PhysAddr, VirtAddr};
|
||||
|
||||
/// A trait implemented in kernel to translate device physical addresses to virtual
|
||||
/// addresses.
|
||||
pub trait IoMapper {
|
||||
/// Translate the device physical address to virtual address. If not mapped
|
||||
/// in the kernel page table, map the region specified by the given `size`.
|
||||
///
|
||||
/// If an error accurs during translation or mapping, returns `None`.
|
||||
fn query_or_map(&self, paddr: PhysAddr, size: usize) -> Option<VirtAddr>;
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#![allow(unused)]
|
||||
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
|
||||
pub mod pci;
|
||||
|
||||
pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
|
||||
unsafe { drivers_phys_to_virt(paddr) }
|
||||
}
|
||||
|
||||
pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
|
||||
unsafe { drivers_virt_to_phys(vaddr) }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn drivers_dma_alloc(pages: usize) -> PhysAddr;
|
||||
fn drivers_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32;
|
||||
fn drivers_phys_to_virt(paddr: PhysAddr) -> VirtAddr;
|
||||
fn drivers_virt_to_phys(vaddr: VirtAddr) -> PhysAddr;
|
||||
}
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
|
||||
type VirtAddr = usize;
|
||||
type PhysAddr = usize;
|
||||
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
#[inline(always)]
|
||||
pub fn write<T>(addr: usize, content: T) {
|
||||
let cell = (addr) as *mut T;
|
||||
unsafe {
|
||||
write_volatile(cell, content);
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn read<T>(addr: usize) -> T {
|
||||
let cell = (addr) as *const T;
|
||||
unsafe { read_volatile(cell) }
|
||||
}
|
||||
|
|
@ -1,327 +0,0 @@
|
|||
use super::{phys_to_virt, PAGE_SIZE};
|
||||
use crate::builder::IoMapper;
|
||||
use crate::{Device, DeviceError, DeviceResult, VirtAddr};
|
||||
use alloc::{collections::BTreeMap, format, sync::Arc, vec::Vec};
|
||||
use pci::*;
|
||||
use spin::Mutex;
|
||||
|
||||
const PCI_COMMAND: u16 = 0x04;
|
||||
const BAR0: u16 = 0x10;
|
||||
const PCI_CAP_PTR: u16 = 0x34;
|
||||
const PCI_INTERRUPT_LINE: u16 = 0x3c;
|
||||
const PCI_INTERRUPT_PIN: u16 = 0x3d;
|
||||
|
||||
const PCI_MSI_CTRL_CAP: u16 = 0x00;
|
||||
const PCI_MSI_ADDR: u16 = 0x04;
|
||||
const PCI_MSI_UPPER_ADDR: u16 = 0x08;
|
||||
const PCI_MSI_DATA_32: u16 = 0x08;
|
||||
const PCI_MSI_DATA_64: u16 = 0x0C;
|
||||
|
||||
const PCI_CAP_ID_MSI: u8 = 0x05;
|
||||
|
||||
struct PortOpsImpl;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
impl PortOps for PortOpsImpl {
|
||||
unsafe fn read8(&self, port: u16) -> u8 {
|
||||
Port::new(port).read()
|
||||
}
|
||||
unsafe fn read16(&self, port: u16) -> u16 {
|
||||
Port::new(port).read()
|
||||
}
|
||||
unsafe fn read32(&self, port: u32) -> u32 {
|
||||
Port::new(port as u16).read()
|
||||
}
|
||||
unsafe fn write8(&self, port: u16, val: u8) {
|
||||
Port::new(port).write(val);
|
||||
}
|
||||
unsafe fn write16(&self, port: u16, val: u16) {
|
||||
Port::new(port).write(val);
|
||||
}
|
||||
unsafe fn write32(&self, port: u32, val: u32) {
|
||||
Port::new(port as u16).write(val);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const PCI_BASE: usize = 0; //Fix me
|
||||
|
||||
#[cfg(any(target_arch = "mips", target_arch = "riscv64"))]
|
||||
use super::{read, write};
|
||||
|
||||
#[cfg(feature = "board_malta")]
|
||||
const PCI_BASE: usize = 0xbbe00000;
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
const PCI_BASE: usize = 0x30000000;
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
const E1000_BASE: usize = 0x40000000;
|
||||
// riscv64 Qemu
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const PCI_ACCESS: CSpaceAccessMethod = CSpaceAccessMethod::IO;
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
const PCI_ACCESS: CSpaceAccessMethod = CSpaceAccessMethod::MemoryMapped(PCI_BASE as *mut u8);
|
||||
|
||||
#[cfg(any(target_arch = "mips", target_arch = "riscv64"))]
|
||||
impl PortOps for PortOpsImpl {
|
||||
unsafe fn read8(&self, port: u16) -> u8 {
|
||||
read(phys_to_virt(PCI_BASE) + port as usize)
|
||||
}
|
||||
unsafe fn read16(&self, port: u16) -> u16 {
|
||||
read(phys_to_virt(PCI_BASE) + port as usize)
|
||||
}
|
||||
unsafe fn read32(&self, port: u32) -> u32 {
|
||||
read(phys_to_virt(PCI_BASE) + port as usize)
|
||||
}
|
||||
unsafe fn write8(&self, port: u16, val: u8) {
|
||||
write(phys_to_virt(PCI_BASE) + port as usize, val);
|
||||
}
|
||||
unsafe fn write16(&self, port: u16, val: u16) {
|
||||
write(phys_to_virt(PCI_BASE) + port as usize, val);
|
||||
}
|
||||
unsafe fn write32(&self, port: u32, val: u32) {
|
||||
write(phys_to_virt(PCI_BASE) + port as usize, val);
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable the pci device and its interrupt
|
||||
/// Return assigned MSI interrupt number when applicable
|
||||
unsafe fn enable(loc: Location, paddr: u64) -> Option<usize> {
|
||||
let ops = &PortOpsImpl;
|
||||
//let am = CSpaceAccessMethod::IO;
|
||||
let am = PCI_ACCESS;
|
||||
|
||||
if paddr != 0 {
|
||||
// reveal PCI regs by setting paddr
|
||||
let bar0_raw = am.read32(ops, loc, BAR0);
|
||||
am.write32(ops, loc, BAR0, (paddr & !0xfff) as u32); //Only for 32-bit decoding
|
||||
debug!(
|
||||
"BAR0 set from {:#x} to {:#x}",
|
||||
bar0_raw,
|
||||
am.read32(ops, loc, BAR0)
|
||||
);
|
||||
}
|
||||
|
||||
// 23 and lower are used
|
||||
static mut MSI_IRQ: u32 = 23;
|
||||
|
||||
let orig = am.read16(ops, loc, PCI_COMMAND);
|
||||
// IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable
|
||||
am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32);
|
||||
|
||||
// find MSI cap
|
||||
let mut msi_found = false;
|
||||
let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16;
|
||||
let mut assigned_irq = None;
|
||||
while cap_ptr > 0 {
|
||||
let cap_id = am.read8(ops, loc, cap_ptr);
|
||||
if cap_id == PCI_CAP_ID_MSI {
|
||||
let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP);
|
||||
// The manual Volume 3 Chapter 10.11 Message Signalled Interrupts
|
||||
// 0 is (usually) the apic id of the bsp.
|
||||
//am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12));
|
||||
am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000);
|
||||
MSI_IRQ += 1;
|
||||
let irq = MSI_IRQ;
|
||||
assigned_irq = Some(irq as usize);
|
||||
// we offset all our irq numbers by 32
|
||||
if (orig_ctrl >> 16) & (1 << 7) != 0 {
|
||||
// 64bit
|
||||
am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_64, irq + 32);
|
||||
} else {
|
||||
// 32bit
|
||||
am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_32, irq + 32);
|
||||
}
|
||||
|
||||
// enable MSI interrupt, assuming 64bit for now
|
||||
am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000);
|
||||
debug!(
|
||||
"MSI control {:#b}, enabling MSI interrupt {}",
|
||||
orig_ctrl >> 16,
|
||||
irq
|
||||
);
|
||||
msi_found = true;
|
||||
}
|
||||
debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr);
|
||||
cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16;
|
||||
}
|
||||
|
||||
if !msi_found {
|
||||
// Use PCI legacy interrupt instead
|
||||
// IO Space | MEM Space | Bus Mastering | Special Cycles
|
||||
am.write32(ops, loc, PCI_COMMAND, (orig | 0xf) as u32);
|
||||
debug!("MSI not found, using PCI interrupt");
|
||||
}
|
||||
|
||||
info!("pci device enable done");
|
||||
|
||||
assigned_irq
|
||||
}
|
||||
|
||||
pub fn init_driver(dev: &PCIDevice, mapper: &Option<Arc<dyn IoMapper>>) -> DeviceResult<Device> {
|
||||
let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function);
|
||||
match (dev.id.vendor_id, dev.id.device_id) {
|
||||
(0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => {
|
||||
// 0x100e
|
||||
// 82540EM Gigabit Ethernet Controller
|
||||
// 0x100f
|
||||
// 82545EM Gigabit Ethernet Controller (Copper)
|
||||
// 0x10d3
|
||||
// 82574L Gigabit Network Connection
|
||||
// (e1000e 8086:10d3)
|
||||
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
|
||||
info!("Found e1000e dev {:?} BAR0 {:#x?}", dev, addr);
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
let addr = if addr == 0 { E1000_BASE as u64 } else { addr };
|
||||
|
||||
if let Some(m) = mapper {
|
||||
m.query_or_map(addr as usize, PAGE_SIZE * 8);
|
||||
}
|
||||
let irq = unsafe { enable(dev.loc, addr) };
|
||||
let vaddr = phys_to_virt(addr as usize);
|
||||
let dev = Device::Net(Arc::new(crate::net::e1000::init(
|
||||
name,
|
||||
irq.unwrap_or(0),
|
||||
vaddr,
|
||||
len as usize,
|
||||
0,
|
||||
)?));
|
||||
return Ok(dev);
|
||||
}
|
||||
}
|
||||
(0x8086, 0x10fb) => {
|
||||
// 82599ES 10-Gigabit SFI/SFP+ Network Connection
|
||||
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
|
||||
let irq = unsafe { enable(dev.loc, 0) };
|
||||
let vaddr = phys_to_virt(addr as usize);
|
||||
info!("Found ixgbe dev {:#x}, irq: {:?}", vaddr, irq);
|
||||
/*
|
||||
let index = NET_DRIVERS.read().len();
|
||||
PCI_DRIVERS.lock().insert(
|
||||
dev.loc,
|
||||
ixgbe::ixgbe_init(name, irq, vaddr, len as usize, index),
|
||||
);
|
||||
*/
|
||||
return Err(DeviceError::NotSupported);
|
||||
}
|
||||
}
|
||||
(0x8086, 0x1533) => {
|
||||
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
|
||||
info!("Intel Corporation I210 Gigabit Network Connection");
|
||||
info!("DEV: {:?}, BAR0: {:#x}", dev, addr);
|
||||
return Err(DeviceError::NotSupported);
|
||||
}
|
||||
}
|
||||
(0x8086, 0x1539) => {
|
||||
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
|
||||
info!(
|
||||
"Found Intel I211 ethernet controller dev {:?}, addr: {:x?}",
|
||||
dev, addr
|
||||
);
|
||||
return Err(DeviceError::NotSupported);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if dev.id.class == 0x01 && dev.id.subclass == 0x06 {
|
||||
// Mass storage class
|
||||
// SATA subclass
|
||||
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] {
|
||||
info!("Found AHCI dev {:?} BAR5 {:x?}", dev, addr);
|
||||
/*
|
||||
let irq = unsafe { enable(dev.loc) };
|
||||
assert!(len as usize <= PAGE_SIZE);
|
||||
let vaddr = phys_to_virt(addr as usize);
|
||||
if let Some(driver) = ahci::init(irq, vaddr, len as usize) {
|
||||
PCI_DRIVERS.lock().insert(dev.loc, driver);
|
||||
}
|
||||
*/
|
||||
return Err(DeviceError::NotSupported);
|
||||
}
|
||||
}
|
||||
|
||||
Err(DeviceError::NoResources)
|
||||
}
|
||||
|
||||
pub fn detach_driver(loc: &Location) -> bool {
|
||||
/*
|
||||
match PCI_DRIVERS.lock().remove(loc) {
|
||||
Some(driver) => {
|
||||
DRIVERS
|
||||
.write()
|
||||
.retain(|dri| dri.get_id() != driver.get_id());
|
||||
NET_DRIVERS
|
||||
.write()
|
||||
.retain(|dri| dri.get_id() != driver.get_id());
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
*/
|
||||
false
|
||||
}
|
||||
|
||||
pub fn init(mapper: Option<Arc<dyn IoMapper>>) -> DeviceResult<Vec<Device>> {
|
||||
let mapper_driver = if let Some(m) = mapper {
|
||||
m.query_or_map(PCI_BASE, PAGE_SIZE * 256 * 32 * 8);
|
||||
Some(m)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut dev_list = Vec::new();
|
||||
let pci_iter = unsafe { scan_bus(&PortOpsImpl, PCI_ACCESS) };
|
||||
info!("");
|
||||
info!("--------- PCI bus:device:function ---------");
|
||||
for dev in pci_iter {
|
||||
info!(
|
||||
"pci: {}:{}:{} {:04x}:{:04x} ({} {}) irq: {}:{:?}",
|
||||
dev.loc.bus,
|
||||
dev.loc.device,
|
||||
dev.loc.function,
|
||||
dev.id.vendor_id,
|
||||
dev.id.device_id,
|
||||
dev.id.class,
|
||||
dev.id.subclass,
|
||||
dev.pic_interrupt_line,
|
||||
dev.interrupt_pin,
|
||||
);
|
||||
let res = init_driver(&dev, &mapper_driver);
|
||||
match res {
|
||||
Ok(d) => dev_list.push(d),
|
||||
Err(e) => warn!(
|
||||
"{:?}, failed to initialize PCI device: {:04x}:{:04x}",
|
||||
e, dev.id.vendor_id, dev.id.device_id
|
||||
),
|
||||
}
|
||||
}
|
||||
info!("---------");
|
||||
info!("");
|
||||
|
||||
Ok(dev_list)
|
||||
}
|
||||
|
||||
pub fn find_device(vendor: u16, product: u16) -> Option<Location> {
|
||||
let pci_iter = unsafe { scan_bus(&PortOpsImpl, PCI_ACCESS) };
|
||||
for dev in pci_iter {
|
||||
if dev.id.vendor_id == vendor && dev.id.device_id == product {
|
||||
return Some(dev.loc);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_bar0_mem(loc: Location) -> Option<(usize, usize)> {
|
||||
unsafe { probe_function(&PortOpsImpl, loc, PCI_ACCESS) }
|
||||
.and_then(|dev| dev.bars[0])
|
||||
.map(|bar| match bar {
|
||||
BAR::Memory(addr, len, _, _) => (addr as usize, len as usize),
|
||||
_ => unimplemented!(),
|
||||
})
|
||||
}
|
||||
|
||||
// all devices stored in:AllDeviceList
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
//! Only UEFI Display currently.
|
||||
|
||||
mod uefi;
|
||||
|
||||
pub use uefi::UefiDisplay;
|
||||
Binary file not shown.
|
|
@ -1,34 +0,0 @@
|
|||
//! UEFI Graphics Output Protocol
|
||||
|
||||
use crate::prelude::{DisplayInfo, FrameBuffer};
|
||||
use crate::scheme::{DisplayScheme, Scheme};
|
||||
|
||||
pub struct UefiDisplay {
|
||||
info: DisplayInfo,
|
||||
}
|
||||
|
||||
impl UefiDisplay {
|
||||
pub fn new(info: DisplayInfo) -> Self {
|
||||
Self { info }
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheme for UefiDisplay {
|
||||
fn name(&self) -> &str {
|
||||
"mock-display"
|
||||
}
|
||||
}
|
||||
|
||||
impl DisplayScheme for UefiDisplay {
|
||||
#[inline]
|
||||
fn info(&self) -> DisplayInfo {
|
||||
self.info
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fb(&self) -> FrameBuffer {
|
||||
unsafe {
|
||||
FrameBuffer::from_raw_parts_mut(self.info.fb_base_vaddr as *mut u8, self.info.fb_size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,808 +0,0 @@
|
|||
//! Linux input event codes.
|
||||
//!
|
||||
//! 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
|
||||
pub const INPUT_PROP_POINTER: u16 = 0x00;
|
||||
/// direct input devices
|
||||
pub const INPUT_PROP_DIRECT: u16 = 0x01;
|
||||
/// has button(s) under pad
|
||||
pub const INPUT_PROP_BUTTONPAD: u16 = 0x02;
|
||||
/// touch rectangle only
|
||||
pub const INPUT_PROP_SEMI_MT: u16 = 0x03;
|
||||
/// softbuttons at top of pad
|
||||
pub const INPUT_PROP_TOPBUTTONPAD: u16 = 0x04;
|
||||
/// is a pointing stick
|
||||
pub const INPUT_PROP_POINTING_STICK: u16 = 0x05;
|
||||
/// has accelerometer
|
||||
pub const INPUT_PROP_ACCELEROMETER: u16 = 0x06;
|
||||
|
||||
pub const INPUT_PROP_MAX: u16 = 0x1f;
|
||||
pub const INPUT_PROP_CNT: u16 = (INPUT_PROP_MAX + 1);
|
||||
}
|
||||
|
||||
/// Event types
|
||||
pub mod ev {
|
||||
pub const EV_SYN: u16 = 0x00;
|
||||
pub const EV_KEY: u16 = 0x01;
|
||||
pub const EV_REL: u16 = 0x02;
|
||||
pub const EV_ABS: u16 = 0x03;
|
||||
pub const EV_MSC: u16 = 0x04;
|
||||
pub const EV_SW: u16 = 0x05;
|
||||
pub const EV_LED: u16 = 0x11;
|
||||
pub const EV_SND: u16 = 0x12;
|
||||
pub const EV_REP: u16 = 0x14;
|
||||
pub const EV_FF: u16 = 0x15;
|
||||
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);
|
||||
}
|
||||
|
||||
/// Synchronization events
|
||||
pub mod syn {
|
||||
pub const SYN_REPORT: u16 = 0;
|
||||
pub const SYN_CONFIG: u16 = 1;
|
||||
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);
|
||||
}
|
||||
|
||||
/// Keys and buttons
|
||||
pub mod key {
|
||||
pub const KEY_RESERVED: u16 = 0;
|
||||
pub const KEY_ESC: u16 = 1;
|
||||
pub const KEY_1: u16 = 2;
|
||||
pub const KEY_2: u16 = 3;
|
||||
pub const KEY_3: u16 = 4;
|
||||
pub const KEY_4: u16 = 5;
|
||||
pub const KEY_5: u16 = 6;
|
||||
pub const KEY_6: u16 = 7;
|
||||
pub const KEY_7: u16 = 8;
|
||||
pub const KEY_8: u16 = 9;
|
||||
pub const KEY_9: u16 = 10;
|
||||
pub const KEY_0: u16 = 11;
|
||||
pub const KEY_MINUS: u16 = 12;
|
||||
pub const KEY_EQUAL: u16 = 13;
|
||||
pub const KEY_BACKSPACE: u16 = 14;
|
||||
pub const KEY_TAB: u16 = 15;
|
||||
pub const KEY_Q: u16 = 16;
|
||||
pub const KEY_W: u16 = 17;
|
||||
pub const KEY_E: u16 = 18;
|
||||
pub const KEY_R: u16 = 19;
|
||||
pub const KEY_T: u16 = 20;
|
||||
pub const KEY_Y: u16 = 21;
|
||||
pub const KEY_U: u16 = 22;
|
||||
pub const KEY_I: u16 = 23;
|
||||
pub const KEY_O: u16 = 24;
|
||||
pub const KEY_P: u16 = 25;
|
||||
pub const KEY_LEFTBRACE: u16 = 26;
|
||||
pub const KEY_RIGHTBRACE: u16 = 27;
|
||||
pub const KEY_ENTER: u16 = 28;
|
||||
pub const KEY_LEFTCTRL: u16 = 29;
|
||||
pub const KEY_A: u16 = 30;
|
||||
pub const KEY_S: u16 = 31;
|
||||
pub const KEY_D: u16 = 32;
|
||||
pub const KEY_F: u16 = 33;
|
||||
pub const KEY_G: u16 = 34;
|
||||
pub const KEY_H: u16 = 35;
|
||||
pub const KEY_J: u16 = 36;
|
||||
pub const KEY_K: u16 = 37;
|
||||
pub const KEY_L: u16 = 38;
|
||||
pub const KEY_SEMICOLON: u16 = 39;
|
||||
pub const KEY_APOSTROPHE: u16 = 40;
|
||||
pub const KEY_GRAVE: u16 = 41;
|
||||
pub const KEY_LEFTSHIFT: u16 = 42;
|
||||
pub const KEY_BACKSLASH: u16 = 43;
|
||||
pub const KEY_Z: u16 = 44;
|
||||
pub const KEY_X: u16 = 45;
|
||||
pub const KEY_C: u16 = 46;
|
||||
pub const KEY_V: u16 = 47;
|
||||
pub const KEY_B: u16 = 48;
|
||||
pub const KEY_N: u16 = 49;
|
||||
pub const KEY_M: u16 = 50;
|
||||
pub const KEY_COMMA: u16 = 51;
|
||||
pub const KEY_DOT: u16 = 52;
|
||||
pub const KEY_SLASH: u16 = 53;
|
||||
pub const KEY_RIGHTSHIFT: u16 = 54;
|
||||
pub const KEY_KPASTERISK: u16 = 55;
|
||||
pub const KEY_LEFTALT: u16 = 56;
|
||||
pub const KEY_SPACE: u16 = 57;
|
||||
pub const KEY_CAPSLOCK: u16 = 58;
|
||||
pub const KEY_F1: u16 = 59;
|
||||
pub const KEY_F2: u16 = 60;
|
||||
pub const KEY_F3: u16 = 61;
|
||||
pub const KEY_F4: u16 = 62;
|
||||
pub const KEY_F5: u16 = 63;
|
||||
pub const KEY_F6: u16 = 64;
|
||||
pub const KEY_F7: u16 = 65;
|
||||
pub const KEY_F8: u16 = 66;
|
||||
pub const KEY_F9: u16 = 67;
|
||||
pub const KEY_F10: u16 = 68;
|
||||
pub const KEY_NUMLOCK: u16 = 69;
|
||||
pub const KEY_SCROLLLOCK: u16 = 70;
|
||||
pub const KEY_KP7: u16 = 71;
|
||||
pub const KEY_KP8: u16 = 72;
|
||||
pub const KEY_KP9: u16 = 73;
|
||||
pub const KEY_KPMINUS: u16 = 74;
|
||||
pub const KEY_KP4: u16 = 75;
|
||||
pub const KEY_KP5: u16 = 76;
|
||||
pub const KEY_KP6: u16 = 77;
|
||||
pub const KEY_KPPLUS: u16 = 78;
|
||||
pub const KEY_KP1: u16 = 79;
|
||||
pub const KEY_KP2: u16 = 80;
|
||||
pub const KEY_KP3: u16 = 81;
|
||||
pub const KEY_KP0: u16 = 82;
|
||||
pub const KEY_KPDOT: u16 = 83;
|
||||
|
||||
pub const KEY_ZENKAKUHANKAKU: u16 = 85;
|
||||
pub const KEY_102ND: u16 = 86;
|
||||
pub const KEY_F11: u16 = 87;
|
||||
pub const KEY_F12: u16 = 88;
|
||||
pub const KEY_RO: u16 = 89;
|
||||
pub const KEY_KATAKANA: u16 = 90;
|
||||
pub const KEY_HIRAGANA: u16 = 91;
|
||||
pub const KEY_HENKAN: u16 = 92;
|
||||
pub const KEY_KATAKANAHIRAGANA: u16 = 93;
|
||||
pub const KEY_MUHENKAN: u16 = 94;
|
||||
pub const KEY_KPJPCOMMA: u16 = 95;
|
||||
pub const KEY_KPENTER: u16 = 96;
|
||||
pub const KEY_RIGHTCTRL: u16 = 97;
|
||||
pub const KEY_KPSLASH: u16 = 98;
|
||||
pub const KEY_SYSRQ: u16 = 99;
|
||||
pub const KEY_RIGHTALT: u16 = 100;
|
||||
pub const KEY_LINEFEED: u16 = 101;
|
||||
pub const KEY_HOME: u16 = 102;
|
||||
pub const KEY_UP: u16 = 103;
|
||||
pub const KEY_PAGEUP: u16 = 104;
|
||||
pub const KEY_LEFT: u16 = 105;
|
||||
pub const KEY_RIGHT: u16 = 106;
|
||||
pub const KEY_END: u16 = 107;
|
||||
pub const KEY_DOWN: u16 = 108;
|
||||
pub const KEY_PAGEDOWN: u16 = 109;
|
||||
pub const KEY_INSERT: u16 = 110;
|
||||
pub const KEY_DELETE: u16 = 111;
|
||||
pub const KEY_MACRO: u16 = 112;
|
||||
pub const KEY_MUTE: u16 = 113;
|
||||
pub const KEY_VOLUMEDOWN: u16 = 114;
|
||||
pub const KEY_VOLUMEUP: u16 = 115;
|
||||
pub const KEY_POWER: u16 = 116;
|
||||
pub const KEY_KPEQUAL: u16 = 117;
|
||||
pub const KEY_KPPLUSMINUS: u16 = 118;
|
||||
pub const KEY_PAUSE: u16 = 119;
|
||||
pub const KEY_SCALE: u16 = 120;
|
||||
|
||||
pub const KEY_KPCOMMA: u16 = 121;
|
||||
pub const KEY_HANGEUL: u16 = 122;
|
||||
pub const KEY_HANGUEL: u16 = KEY_HANGEUL;
|
||||
pub const KEY_HANJA: u16 = 123;
|
||||
pub const KEY_YEN: u16 = 124;
|
||||
pub const KEY_LEFTMETA: u16 = 125;
|
||||
pub const KEY_RIGHTMETA: u16 = 126;
|
||||
pub const KEY_COMPOSE: u16 = 127;
|
||||
|
||||
pub const KEY_STOP: u16 = 128;
|
||||
pub const KEY_AGAIN: u16 = 129;
|
||||
pub const KEY_PROPS: u16 = 130;
|
||||
pub const KEY_UNDO: u16 = 131;
|
||||
pub const KEY_FRONT: u16 = 132;
|
||||
pub const KEY_COPY: u16 = 133;
|
||||
pub const KEY_OPEN: u16 = 134;
|
||||
pub const KEY_PASTE: u16 = 135;
|
||||
pub const KEY_FIND: u16 = 136;
|
||||
pub const KEY_CUT: u16 = 137;
|
||||
pub const KEY_HELP: u16 = 138;
|
||||
pub const KEY_MENU: u16 = 139;
|
||||
pub const KEY_CALC: u16 = 140;
|
||||
pub const KEY_SETUP: u16 = 141;
|
||||
pub const KEY_SLEEP: u16 = 142;
|
||||
pub const KEY_WAKEUP: u16 = 143;
|
||||
pub const KEY_FILE: u16 = 144;
|
||||
pub const KEY_SENDFILE: u16 = 145;
|
||||
pub const KEY_DELETEFILE: u16 = 146;
|
||||
pub const KEY_XFER: u16 = 147;
|
||||
pub const KEY_PROG1: u16 = 148;
|
||||
pub const KEY_PROG2: u16 = 149;
|
||||
pub const KEY_WWW: u16 = 150;
|
||||
pub const KEY_MSDOS: u16 = 151;
|
||||
pub const KEY_COFFEE: u16 = 152;
|
||||
pub const KEY_SCREENLOCK: u16 = KEY_COFFEE;
|
||||
pub const KEY_ROTATE_DISPLAY: u16 = 153;
|
||||
pub const KEY_DIRECTION: u16 = KEY_ROTATE_DISPLAY;
|
||||
pub const KEY_CYCLEWINDOWS: u16 = 154;
|
||||
pub const KEY_MAIL: u16 = 155;
|
||||
pub const KEY_BOOKMARKS: u16 = 156;
|
||||
pub const KEY_COMPUTER: u16 = 157;
|
||||
pub const KEY_BACK: u16 = 158;
|
||||
pub const KEY_FORWARD: u16 = 159;
|
||||
pub const KEY_CLOSECD: u16 = 160;
|
||||
pub const KEY_EJECTCD: u16 = 161;
|
||||
pub const KEY_EJECTCLOSECD: u16 = 162;
|
||||
pub const KEY_NEXTSONG: u16 = 163;
|
||||
pub const KEY_PLAYPAUSE: u16 = 164;
|
||||
pub const KEY_PREVIOUSSONG: u16 = 165;
|
||||
pub const KEY_STOPCD: u16 = 166;
|
||||
pub const KEY_RECORD: u16 = 167;
|
||||
pub const KEY_REWIND: u16 = 168;
|
||||
pub const KEY_PHONE: u16 = 169;
|
||||
pub const KEY_ISO: u16 = 170;
|
||||
pub const KEY_CONFIG: u16 = 171;
|
||||
pub const KEY_HOMEPAGE: u16 = 172;
|
||||
pub const KEY_REFRESH: u16 = 173;
|
||||
pub const KEY_EXIT: u16 = 174;
|
||||
pub const KEY_MOVE: u16 = 175;
|
||||
pub const KEY_EDIT: u16 = 176;
|
||||
pub const KEY_SCROLLUP: u16 = 177;
|
||||
pub const KEY_SCROLLDOWN: u16 = 178;
|
||||
pub const KEY_KPLEFTPAREN: u16 = 179;
|
||||
pub const KEY_KPRIGHTPAREN: u16 = 180;
|
||||
pub const KEY_NEW: u16 = 181;
|
||||
pub const KEY_REDO: u16 = 182;
|
||||
|
||||
pub const KEY_F13: u16 = 183;
|
||||
pub const KEY_F14: u16 = 184;
|
||||
pub const KEY_F15: u16 = 185;
|
||||
pub const KEY_F16: u16 = 186;
|
||||
pub const KEY_F17: u16 = 187;
|
||||
pub const KEY_F18: u16 = 188;
|
||||
pub const KEY_F19: u16 = 189;
|
||||
pub const KEY_F20: u16 = 190;
|
||||
pub const KEY_F21: u16 = 191;
|
||||
pub const KEY_F22: u16 = 192;
|
||||
pub const KEY_F23: u16 = 193;
|
||||
pub const KEY_F24: u16 = 194;
|
||||
|
||||
pub const KEY_PLAYCD: u16 = 200;
|
||||
pub const KEY_PAUSECD: u16 = 201;
|
||||
pub const KEY_PROG3: u16 = 202;
|
||||
pub const KEY_PROG4: u16 = 203;
|
||||
pub const KEY_DASHBOARD: u16 = 204;
|
||||
pub const KEY_SUSPEND: u16 = 205;
|
||||
pub const KEY_CLOSE: u16 = 206;
|
||||
pub const KEY_PLAY: u16 = 207;
|
||||
pub const KEY_FASTFORWARD: u16 = 208;
|
||||
pub const KEY_BASSBOOST: u16 = 209;
|
||||
pub const KEY_PRINT: u16 = 210;
|
||||
pub const KEY_HP: u16 = 211;
|
||||
pub const KEY_CAMERA: u16 = 212;
|
||||
pub const KEY_SOUND: u16 = 213;
|
||||
pub const KEY_QUESTION: u16 = 214;
|
||||
pub const KEY_EMAIL: u16 = 215;
|
||||
pub const KEY_CHAT: u16 = 216;
|
||||
pub const KEY_SEARCH: u16 = 217;
|
||||
pub const KEY_CONNECT: u16 = 218;
|
||||
pub const KEY_FINANCE: u16 = 219;
|
||||
pub const KEY_SPORT: u16 = 220;
|
||||
pub const KEY_SHOP: u16 = 221;
|
||||
pub const KEY_ALTERASE: u16 = 222;
|
||||
pub const KEY_CANCEL: u16 = 223;
|
||||
pub const KEY_BRIGHTNESSDOWN: u16 = 224;
|
||||
pub const KEY_BRIGHTNESSUP: u16 = 225;
|
||||
pub const KEY_MEDIA: u16 = 226;
|
||||
|
||||
pub const KEY_SWITCHVIDEOMODE: u16 = 227;
|
||||
pub const KEY_KBDILLUMTOGGLE: u16 = 228;
|
||||
pub const KEY_KBDILLUMDOWN: u16 = 229;
|
||||
pub const KEY_KBDILLUMUP: u16 = 230;
|
||||
|
||||
pub const KEY_SEND: u16 = 231;
|
||||
pub const KEY_REPLY: u16 = 232;
|
||||
pub const KEY_FORWARDMAIL: u16 = 233;
|
||||
pub const KEY_SAVE: u16 = 234;
|
||||
pub const KEY_DOCUMENTS: u16 = 235;
|
||||
|
||||
pub const KEY_BATTERY: u16 = 236;
|
||||
|
||||
pub const KEY_BLUETOOTH: u16 = 237;
|
||||
pub const KEY_WLAN: u16 = 238;
|
||||
pub const KEY_UWB: u16 = 239;
|
||||
|
||||
pub const KEY_UNKNOWN: u16 = 240;
|
||||
|
||||
pub const KEY_VIDEO_NEXT: u16 = 241;
|
||||
pub const KEY_VIDEO_PREV: u16 = 242;
|
||||
pub const KEY_BRIGHTNESS_CYCLE: u16 = 243;
|
||||
pub const KEY_BRIGHTNESS_AUTO: u16 = 244;
|
||||
pub const KEY_BRIGHTNESS_ZERO: u16 = KEY_BRIGHTNESS_AUTO;
|
||||
pub const KEY_DISPLAY_OFF: u16 = 245;
|
||||
|
||||
pub const KEY_WWAN: u16 = 246;
|
||||
pub const KEY_WIMAX: u16 = KEY_WWAN;
|
||||
pub const KEY_RFKILL: u16 = 247;
|
||||
|
||||
pub const KEY_MICMUTE: u16 = 248;
|
||||
|
||||
pub const BTN_MISC: u16 = 0x100;
|
||||
pub const BTN_0: u16 = 0x100;
|
||||
pub const BTN_1: u16 = 0x101;
|
||||
pub const BTN_2: u16 = 0x102;
|
||||
pub const BTN_3: u16 = 0x103;
|
||||
pub const BTN_4: u16 = 0x104;
|
||||
pub const BTN_5: u16 = 0x105;
|
||||
pub const BTN_6: u16 = 0x106;
|
||||
pub const BTN_7: u16 = 0x107;
|
||||
pub const BTN_8: u16 = 0x108;
|
||||
pub const BTN_9: u16 = 0x109;
|
||||
|
||||
pub const BTN_MOUSE: u16 = 0x110;
|
||||
pub const BTN_LEFT: u16 = 0x110;
|
||||
pub const BTN_RIGHT: u16 = 0x111;
|
||||
pub const BTN_MIDDLE: u16 = 0x112;
|
||||
pub const BTN_SIDE: u16 = 0x113;
|
||||
pub const BTN_EXTRA: u16 = 0x114;
|
||||
pub const BTN_FORWARD: u16 = 0x115;
|
||||
pub const BTN_BACK: u16 = 0x116;
|
||||
pub const BTN_TASK: u16 = 0x117;
|
||||
|
||||
pub const BTN_JOYSTICK: u16 = 0x120;
|
||||
pub const BTN_TRIGGER: u16 = 0x120;
|
||||
pub const BTN_THUMB: u16 = 0x121;
|
||||
pub const BTN_THUMB2: u16 = 0x122;
|
||||
pub const BTN_TOP: u16 = 0x123;
|
||||
pub const BTN_TOP2: u16 = 0x124;
|
||||
pub const BTN_PINKIE: u16 = 0x125;
|
||||
pub const BTN_BASE: u16 = 0x126;
|
||||
pub const BTN_BASE2: u16 = 0x127;
|
||||
pub const BTN_BASE3: u16 = 0x128;
|
||||
pub const BTN_BASE4: u16 = 0x129;
|
||||
pub const BTN_BASE5: u16 = 0x12a;
|
||||
pub const BTN_BASE6: u16 = 0x12b;
|
||||
pub const BTN_DEAD: u16 = 0x12f;
|
||||
|
||||
pub const BTN_GAMEPAD: u16 = 0x130;
|
||||
pub const BTN_SOUTH: u16 = 0x130;
|
||||
pub const BTN_A: u16 = BTN_SOUTH;
|
||||
pub const BTN_EAST: u16 = 0x131;
|
||||
pub const BTN_B: u16 = BTN_EAST;
|
||||
pub const BTN_C: u16 = 0x132;
|
||||
pub const BTN_NORTH: u16 = 0x133;
|
||||
pub const BTN_X: u16 = BTN_NORTH;
|
||||
pub const BTN_WEST: u16 = 0x134;
|
||||
pub const BTN_Y: u16 = BTN_WEST;
|
||||
pub const BTN_Z: u16 = 0x135;
|
||||
pub const BTN_TL: u16 = 0x136;
|
||||
pub const BTN_TR: u16 = 0x137;
|
||||
pub const BTN_TL2: u16 = 0x138;
|
||||
pub const BTN_TR2: u16 = 0x139;
|
||||
pub const BTN_SELECT: u16 = 0x13a;
|
||||
pub const BTN_START: u16 = 0x13b;
|
||||
pub const BTN_MODE: u16 = 0x13c;
|
||||
pub const BTN_THUMBL: u16 = 0x13d;
|
||||
pub const BTN_THUMBR: u16 = 0x13e;
|
||||
|
||||
pub const BTN_DIGI: u16 = 0x140;
|
||||
pub const BTN_TOOL_PEN: u16 = 0x140;
|
||||
pub const BTN_TOOL_RUBBER: u16 = 0x141;
|
||||
pub const BTN_TOOL_BRUSH: u16 = 0x142;
|
||||
pub const BTN_TOOL_PENCIL: u16 = 0x143;
|
||||
pub const BTN_TOOL_AIRBRUSH: u16 = 0x144;
|
||||
pub const BTN_TOOL_FINGER: u16 = 0x145;
|
||||
pub const BTN_TOOL_MOUSE: u16 = 0x146;
|
||||
pub const BTN_TOOL_LENS: u16 = 0x147;
|
||||
pub const BTN_TOOL_QUINTTAP: u16 = 0x148;
|
||||
pub const BTN_STYLUS3: u16 = 0x149;
|
||||
pub const BTN_TOUCH: u16 = 0x14a;
|
||||
pub const BTN_STYLUS: u16 = 0x14b;
|
||||
pub const BTN_STYLUS2: u16 = 0x14c;
|
||||
pub const BTN_TOOL_DOUBLETAP: u16 = 0x14d;
|
||||
pub const BTN_TOOL_TRIPLETAP: u16 = 0x14e;
|
||||
pub const BTN_TOOL_QUADTAP: u16 = 0x14f;
|
||||
|
||||
pub const BTN_WHEEL: u16 = 0x150;
|
||||
pub const BTN_GEAR_DOWN: u16 = 0x150;
|
||||
pub const BTN_GEAR_UP: u16 = 0x151;
|
||||
|
||||
pub const KEY_OK: u16 = 0x160;
|
||||
pub const KEY_SELECT: u16 = 0x161;
|
||||
pub const KEY_GOTO: u16 = 0x162;
|
||||
pub const KEY_CLEAR: u16 = 0x163;
|
||||
pub const KEY_POWER2: u16 = 0x164;
|
||||
pub const KEY_OPTION: u16 = 0x165;
|
||||
pub const KEY_INFO: u16 = 0x166;
|
||||
pub const KEY_TIME: u16 = 0x167;
|
||||
pub const KEY_VENDOR: u16 = 0x168;
|
||||
pub const KEY_ARCHIVE: u16 = 0x169;
|
||||
pub const KEY_PROGRAM: u16 = 0x16a;
|
||||
pub const KEY_CHANNEL: u16 = 0x16b;
|
||||
pub const KEY_FAVORITES: u16 = 0x16c;
|
||||
pub const KEY_EPG: u16 = 0x16d;
|
||||
pub const KEY_PVR: u16 = 0x16e;
|
||||
pub const KEY_MHP: u16 = 0x16f;
|
||||
pub const KEY_LANGUAGE: u16 = 0x170;
|
||||
pub const KEY_TITLE: u16 = 0x171;
|
||||
pub const KEY_SUBTITLE: u16 = 0x172;
|
||||
pub const KEY_ANGLE: u16 = 0x173;
|
||||
pub const KEY_FULL_SCREEN: u16 = 0x174;
|
||||
pub const KEY_ZOOM: u16 = KEY_FULL_SCREEN;
|
||||
pub const KEY_MODE: u16 = 0x175;
|
||||
pub const KEY_KEYBOARD: u16 = 0x176;
|
||||
pub const KEY_ASPECT_RATIO: u16 = 0x177;
|
||||
pub const KEY_SCREEN: u16 = KEY_ASPECT_RATIO;
|
||||
pub const KEY_PC: u16 = 0x178;
|
||||
pub const KEY_TV: u16 = 0x179;
|
||||
pub const KEY_TV2: u16 = 0x17a;
|
||||
pub const KEY_VCR: u16 = 0x17b;
|
||||
pub const KEY_VCR2: u16 = 0x17c;
|
||||
pub const KEY_SAT: u16 = 0x17d;
|
||||
pub const KEY_SAT2: u16 = 0x17e;
|
||||
pub const KEY_CD: u16 = 0x17f;
|
||||
pub const KEY_TAPE: u16 = 0x180;
|
||||
pub const KEY_RADIO: u16 = 0x181;
|
||||
pub const KEY_TUNER: u16 = 0x182;
|
||||
pub const KEY_PLAYER: u16 = 0x183;
|
||||
pub const KEY_TEXT: u16 = 0x184;
|
||||
pub const KEY_DVD: u16 = 0x185;
|
||||
pub const KEY_AUX: u16 = 0x186;
|
||||
pub const KEY_MP3: u16 = 0x187;
|
||||
pub const KEY_AUDIO: u16 = 0x188;
|
||||
pub const KEY_VIDEO: u16 = 0x189;
|
||||
pub const KEY_DIRECTORY: u16 = 0x18a;
|
||||
pub const KEY_LIST: u16 = 0x18b;
|
||||
pub const KEY_MEMO: u16 = 0x18c;
|
||||
pub const KEY_CALENDAR: u16 = 0x18d;
|
||||
pub const KEY_RED: u16 = 0x18e;
|
||||
pub const KEY_GREEN: u16 = 0x18f;
|
||||
pub const KEY_YELLOW: u16 = 0x190;
|
||||
pub const KEY_BLUE: u16 = 0x191;
|
||||
pub const KEY_CHANNELUP: u16 = 0x192;
|
||||
pub const KEY_CHANNELDOWN: u16 = 0x193;
|
||||
pub const KEY_FIRST: u16 = 0x194;
|
||||
pub const KEY_LAST: u16 = 0x195;
|
||||
pub const KEY_AB: u16 = 0x196;
|
||||
pub const KEY_NEXT: u16 = 0x197;
|
||||
pub const KEY_RESTART: u16 = 0x198;
|
||||
pub const KEY_SLOW: u16 = 0x199;
|
||||
pub const KEY_SHUFFLE: u16 = 0x19a;
|
||||
pub const KEY_BREAK: u16 = 0x19b;
|
||||
pub const KEY_PREVIOUS: u16 = 0x19c;
|
||||
pub const KEY_DIGITS: u16 = 0x19d;
|
||||
pub const KEY_TEEN: u16 = 0x19e;
|
||||
pub const KEY_TWEN: u16 = 0x19f;
|
||||
pub const KEY_VIDEOPHONE: u16 = 0x1a0;
|
||||
pub const KEY_GAMES: u16 = 0x1a1;
|
||||
pub const KEY_ZOOMIN: u16 = 0x1a2;
|
||||
pub const KEY_ZOOMOUT: u16 = 0x1a3;
|
||||
pub const KEY_ZOOMRESET: u16 = 0x1a4;
|
||||
pub const KEY_WORDPROCESSOR: u16 = 0x1a5;
|
||||
pub const KEY_EDITOR: u16 = 0x1a6;
|
||||
pub const KEY_SPREADSHEET: u16 = 0x1a7;
|
||||
pub const KEY_GRAPHICSEDITOR: u16 = 0x1a8;
|
||||
pub const KEY_PRESENTATION: u16 = 0x1a9;
|
||||
pub const KEY_DATABASE: u16 = 0x1aa;
|
||||
pub const KEY_NEWS: u16 = 0x1ab;
|
||||
pub const KEY_VOICEMAIL: u16 = 0x1ac;
|
||||
pub const KEY_ADDRESSBOOK: u16 = 0x1ad;
|
||||
pub const KEY_MESSENGER: u16 = 0x1ae;
|
||||
pub const KEY_DISPLAYTOGGLE: u16 = 0x1af;
|
||||
pub const KEY_BRIGHTNESS_TOGGLE: u16 = KEY_DISPLAYTOGGLE;
|
||||
pub const KEY_SPELLCHECK: u16 = 0x1b0;
|
||||
pub const KEY_LOGOFF: u16 = 0x1b1;
|
||||
|
||||
pub const KEY_DOLLAR: u16 = 0x1b2;
|
||||
pub const KEY_EURO: u16 = 0x1b3;
|
||||
|
||||
pub const KEY_FRAMEBACK: u16 = 0x1b4;
|
||||
pub const KEY_FRAMEFORWARD: u16 = 0x1b5;
|
||||
pub const KEY_CONTEXT_MENU: u16 = 0x1b6;
|
||||
pub const KEY_MEDIA_REPEAT: u16 = 0x1b7;
|
||||
pub const KEY_10CHANNELSUP: u16 = 0x1b8;
|
||||
pub const KEY_10CHANNELSDOWN: u16 = 0x1b9;
|
||||
pub const KEY_IMAGES: u16 = 0x1ba;
|
||||
|
||||
pub const KEY_DEL_EOL: u16 = 0x1c0;
|
||||
pub const KEY_DEL_EOS: u16 = 0x1c1;
|
||||
pub const KEY_INS_LINE: u16 = 0x1c2;
|
||||
pub const KEY_DEL_LINE: u16 = 0x1c3;
|
||||
|
||||
pub const KEY_FN: u16 = 0x1d0;
|
||||
pub const KEY_FN_ESC: u16 = 0x1d1;
|
||||
pub const KEY_FN_F1: u16 = 0x1d2;
|
||||
pub const KEY_FN_F2: u16 = 0x1d3;
|
||||
pub const KEY_FN_F3: u16 = 0x1d4;
|
||||
pub const KEY_FN_F4: u16 = 0x1d5;
|
||||
pub const KEY_FN_F5: u16 = 0x1d6;
|
||||
pub const KEY_FN_F6: u16 = 0x1d7;
|
||||
pub const KEY_FN_F7: u16 = 0x1d8;
|
||||
pub const KEY_FN_F8: u16 = 0x1d9;
|
||||
pub const KEY_FN_F9: u16 = 0x1da;
|
||||
pub const KEY_FN_F10: u16 = 0x1db;
|
||||
pub const KEY_FN_F11: u16 = 0x1dc;
|
||||
pub const KEY_FN_F12: u16 = 0x1dd;
|
||||
pub const KEY_FN_1: u16 = 0x1de;
|
||||
pub const KEY_FN_2: u16 = 0x1df;
|
||||
pub const KEY_FN_D: u16 = 0x1e0;
|
||||
pub const KEY_FN_E: u16 = 0x1e1;
|
||||
pub const KEY_FN_F: u16 = 0x1e2;
|
||||
pub const KEY_FN_S: u16 = 0x1e3;
|
||||
pub const KEY_FN_B: u16 = 0x1e4;
|
||||
|
||||
pub const KEY_BRL_DOT1: u16 = 0x1f1;
|
||||
pub const KEY_BRL_DOT2: u16 = 0x1f2;
|
||||
pub const KEY_BRL_DOT3: u16 = 0x1f3;
|
||||
pub const KEY_BRL_DOT4: u16 = 0x1f4;
|
||||
pub const KEY_BRL_DOT5: u16 = 0x1f5;
|
||||
pub const KEY_BRL_DOT6: u16 = 0x1f6;
|
||||
pub const KEY_BRL_DOT7: u16 = 0x1f7;
|
||||
pub const KEY_BRL_DOT8: u16 = 0x1f8;
|
||||
pub const KEY_BRL_DOT9: u16 = 0x1f9;
|
||||
pub const KEY_BRL_DOT10: u16 = 0x1fa;
|
||||
|
||||
pub const KEY_NUMERIC_0: u16 = 0x200;
|
||||
pub const KEY_NUMERIC_1: u16 = 0x201;
|
||||
pub const KEY_NUMERIC_2: u16 = 0x202;
|
||||
pub const KEY_NUMERIC_3: u16 = 0x203;
|
||||
pub const KEY_NUMERIC_4: u16 = 0x204;
|
||||
pub const KEY_NUMERIC_5: u16 = 0x205;
|
||||
pub const KEY_NUMERIC_6: u16 = 0x206;
|
||||
pub const KEY_NUMERIC_7: u16 = 0x207;
|
||||
pub const KEY_NUMERIC_8: u16 = 0x208;
|
||||
pub const KEY_NUMERIC_9: u16 = 0x209;
|
||||
pub const KEY_NUMERIC_STAR: u16 = 0x20a;
|
||||
pub const KEY_NUMERIC_POUND: u16 = 0x20b;
|
||||
pub const KEY_NUMERIC_A: u16 = 0x20c;
|
||||
pub const KEY_NUMERIC_B: u16 = 0x20d;
|
||||
pub const KEY_NUMERIC_C: u16 = 0x20e;
|
||||
pub const KEY_NUMERIC_D: u16 = 0x20f;
|
||||
|
||||
pub const KEY_CAMERA_FOCUS: u16 = 0x210;
|
||||
pub const KEY_WPS_BUTTON: u16 = 0x211;
|
||||
|
||||
pub const KEY_TOUCHPAD_TOGGLE: u16 = 0x212;
|
||||
pub const KEY_TOUCHPAD_ON: u16 = 0x213;
|
||||
pub const KEY_TOUCHPAD_OFF: u16 = 0x214;
|
||||
|
||||
pub const KEY_CAMERA_ZOOMIN: u16 = 0x215;
|
||||
pub const KEY_CAMERA_ZOOMOUT: u16 = 0x216;
|
||||
pub const KEY_CAMERA_UP: u16 = 0x217;
|
||||
pub const KEY_CAMERA_DOWN: u16 = 0x218;
|
||||
pub const KEY_CAMERA_LEFT: u16 = 0x219;
|
||||
pub const KEY_CAMERA_RIGHT: u16 = 0x21a;
|
||||
|
||||
pub const KEY_ATTENDANT_ON: u16 = 0x21b;
|
||||
pub const KEY_ATTENDANT_OFF: u16 = 0x21c;
|
||||
pub const KEY_ATTENDANT_TOGGLE: u16 = 0x21d;
|
||||
pub const KEY_LIGHTS_TOGGLE: u16 = 0x21e;
|
||||
|
||||
pub const BTN_DPAD_UP: u16 = 0x220;
|
||||
pub const BTN_DPAD_DOWN: u16 = 0x221;
|
||||
pub const BTN_DPAD_LEFT: u16 = 0x222;
|
||||
pub const BTN_DPAD_RIGHT: u16 = 0x223;
|
||||
|
||||
pub const KEY_ALS_TOGGLE: u16 = 0x230;
|
||||
pub const KEY_ROTATE_LOCK_TOGGLE: u16 = 0x231;
|
||||
|
||||
pub const KEY_BUTTONCONFIG: u16 = 0x240;
|
||||
pub const KEY_TASKMANAGER: u16 = 0x241;
|
||||
pub const KEY_JOURNAL: u16 = 0x242;
|
||||
pub const KEY_CONTROLPANEL: u16 = 0x243;
|
||||
pub const KEY_APPSELECT: u16 = 0x244;
|
||||
pub const KEY_SCREENSAVER: u16 = 0x245;
|
||||
pub const KEY_VOICECOMMAND: u16 = 0x246;
|
||||
pub const KEY_ASSISTANT: u16 = 0x247;
|
||||
|
||||
pub const KEY_BRIGHTNESS_MIN: u16 = 0x250;
|
||||
pub const KEY_BRIGHTNESS_MAX: u16 = 0x251;
|
||||
|
||||
pub const KEY_KBDINPUTASSIST_PREV: u16 = 0x260;
|
||||
pub const KEY_KBDINPUTASSIST_NEXT: u16 = 0x261;
|
||||
pub const KEY_KBDINPUTASSIST_PREVGROUP: u16 = 0x262;
|
||||
pub const KEY_KBDINPUTASSIST_NEXTGROUP: u16 = 0x263;
|
||||
pub const KEY_KBDINPUTASSIST_ACCEPT: u16 = 0x264;
|
||||
pub const KEY_KBDINPUTASSIST_CANCEL: u16 = 0x265;
|
||||
|
||||
pub const KEY_RIGHT_UP: u16 = 0x266;
|
||||
pub const KEY_RIGHT_DOWN: u16 = 0x267;
|
||||
pub const KEY_LEFT_UP: u16 = 0x268;
|
||||
pub const KEY_LEFT_DOWN: u16 = 0x269;
|
||||
|
||||
pub const KEY_ROOT_MENU: u16 = 0x26a;
|
||||
pub const KEY_MEDIA_TOP_MENU: u16 = 0x26b;
|
||||
pub const KEY_NUMERIC_11: u16 = 0x26c;
|
||||
pub const KEY_NUMERIC_12: u16 = 0x26d;
|
||||
pub const KEY_AUDIO_DESC: u16 = 0x26e;
|
||||
pub const KEY_3D_MODE: u16 = 0x26f;
|
||||
pub const KEY_NEXT_FAVORITE: u16 = 0x270;
|
||||
pub const KEY_STOP_RECORD: u16 = 0x271;
|
||||
pub const KEY_PAUSE_RECORD: u16 = 0x272;
|
||||
pub const KEY_VOD: u16 = 0x273;
|
||||
pub const KEY_UNMUTE: u16 = 0x274;
|
||||
pub const KEY_FASTREVERSE: u16 = 0x275;
|
||||
pub const KEY_SLOWREVERSE: u16 = 0x276;
|
||||
pub const KEY_DATA: u16 = 0x277;
|
||||
pub const KEY_ONSCREEN_KEYBOARD: u16 = 0x278;
|
||||
|
||||
pub const BTN_TRIGGER_HAPPY: u16 = 0x2c0;
|
||||
pub const BTN_TRIGGER_HAPPY1: u16 = 0x2c0;
|
||||
pub const BTN_TRIGGER_HAPPY2: u16 = 0x2c1;
|
||||
pub const BTN_TRIGGER_HAPPY3: u16 = 0x2c2;
|
||||
pub const BTN_TRIGGER_HAPPY4: u16 = 0x2c3;
|
||||
pub const BTN_TRIGGER_HAPPY5: u16 = 0x2c4;
|
||||
pub const BTN_TRIGGER_HAPPY6: u16 = 0x2c5;
|
||||
pub const BTN_TRIGGER_HAPPY7: u16 = 0x2c6;
|
||||
pub const BTN_TRIGGER_HAPPY8: u16 = 0x2c7;
|
||||
pub const BTN_TRIGGER_HAPPY9: u16 = 0x2c8;
|
||||
pub const BTN_TRIGGER_HAPPY10: u16 = 0x2c9;
|
||||
pub const BTN_TRIGGER_HAPPY11: u16 = 0x2ca;
|
||||
pub const BTN_TRIGGER_HAPPY12: u16 = 0x2cb;
|
||||
pub const BTN_TRIGGER_HAPPY13: u16 = 0x2cc;
|
||||
pub const BTN_TRIGGER_HAPPY14: u16 = 0x2cd;
|
||||
pub const BTN_TRIGGER_HAPPY15: u16 = 0x2ce;
|
||||
pub const BTN_TRIGGER_HAPPY16: u16 = 0x2cf;
|
||||
pub const BTN_TRIGGER_HAPPY17: u16 = 0x2d0;
|
||||
pub const BTN_TRIGGER_HAPPY18: u16 = 0x2d1;
|
||||
pub const BTN_TRIGGER_HAPPY19: u16 = 0x2d2;
|
||||
pub const BTN_TRIGGER_HAPPY20: u16 = 0x2d3;
|
||||
pub const BTN_TRIGGER_HAPPY21: u16 = 0x2d4;
|
||||
pub const BTN_TRIGGER_HAPPY22: u16 = 0x2d5;
|
||||
pub const BTN_TRIGGER_HAPPY23: u16 = 0x2d6;
|
||||
pub const BTN_TRIGGER_HAPPY24: u16 = 0x2d7;
|
||||
pub const BTN_TRIGGER_HAPPY25: u16 = 0x2d8;
|
||||
pub const BTN_TRIGGER_HAPPY26: u16 = 0x2d9;
|
||||
pub const BTN_TRIGGER_HAPPY27: u16 = 0x2da;
|
||||
pub const BTN_TRIGGER_HAPPY28: u16 = 0x2db;
|
||||
pub const BTN_TRIGGER_HAPPY29: u16 = 0x2dc;
|
||||
pub const BTN_TRIGGER_HAPPY30: u16 = 0x2dd;
|
||||
pub const BTN_TRIGGER_HAPPY31: u16 = 0x2de;
|
||||
pub const BTN_TRIGGER_HAPPY32: u16 = 0x2df;
|
||||
pub const BTN_TRIGGER_HAPPY33: u16 = 0x2e0;
|
||||
pub const BTN_TRIGGER_HAPPY34: u16 = 0x2e1;
|
||||
pub const BTN_TRIGGER_HAPPY35: u16 = 0x2e2;
|
||||
pub const BTN_TRIGGER_HAPPY36: u16 = 0x2e3;
|
||||
pub const BTN_TRIGGER_HAPPY37: u16 = 0x2e4;
|
||||
pub const BTN_TRIGGER_HAPPY38: u16 = 0x2e5;
|
||||
pub const BTN_TRIGGER_HAPPY39: u16 = 0x2e6;
|
||||
pub const BTN_TRIGGER_HAPPY40: u16 = 0x2e7;
|
||||
|
||||
pub const KEY_MIN_INTERESTING: u16 = KEY_MUTE;
|
||||
pub const KEY_MAX: u16 = 0x2ff;
|
||||
pub const KEY_CNT: u16 = (KEY_MAX + 1);
|
||||
}
|
||||
|
||||
/// Relative axes
|
||||
pub mod rel {
|
||||
pub const REL_X: u16 = 0x00;
|
||||
pub const REL_Y: u16 = 0x01;
|
||||
pub const REL_Z: u16 = 0x02;
|
||||
pub const REL_RX: u16 = 0x03;
|
||||
pub const REL_RY: u16 = 0x04;
|
||||
pub const REL_RZ: u16 = 0x05;
|
||||
pub const REL_HWHEEL: u16 = 0x06;
|
||||
pub const REL_DIAL: u16 = 0x07;
|
||||
pub const REL_WHEEL: u16 = 0x08;
|
||||
pub const REL_MISC: u16 = 0x09;
|
||||
|
||||
pub const REL_RESERVED: u16 = 0x0a;
|
||||
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);
|
||||
}
|
||||
|
||||
/// Absolute axes
|
||||
pub mod abs {
|
||||
pub const ABS_X: u16 = 0x00;
|
||||
pub const ABS_Y: u16 = 0x01;
|
||||
pub const ABS_Z: u16 = 0x02;
|
||||
pub const ABS_RX: u16 = 0x03;
|
||||
pub const ABS_RY: u16 = 0x04;
|
||||
pub const ABS_RZ: u16 = 0x05;
|
||||
pub const ABS_THROTTLE: u16 = 0x06;
|
||||
pub const ABS_RUDDER: u16 = 0x07;
|
||||
pub const ABS_WHEEL: u16 = 0x08;
|
||||
pub const ABS_GAS: u16 = 0x09;
|
||||
pub const ABS_BRAKE: u16 = 0x0a;
|
||||
pub const ABS_HAT0X: u16 = 0x10;
|
||||
pub const ABS_HAT0Y: u16 = 0x11;
|
||||
pub const ABS_HAT1X: u16 = 0x12;
|
||||
pub const ABS_HAT1Y: u16 = 0x13;
|
||||
pub const ABS_HAT2X: u16 = 0x14;
|
||||
pub const ABS_HAT2Y: u16 = 0x15;
|
||||
pub const ABS_HAT3X: u16 = 0x16;
|
||||
pub const ABS_HAT3Y: u16 = 0x17;
|
||||
pub const ABS_PRESSURE: u16 = 0x18;
|
||||
pub const ABS_DISTANCE: u16 = 0x19;
|
||||
pub const ABS_TILT_X: u16 = 0x1a;
|
||||
pub const ABS_TILT_Y: u16 = 0x1b;
|
||||
pub const ABS_TOOL_WIDTH: u16 = 0x1c;
|
||||
|
||||
pub const ABS_VOLUME: u16 = 0x20;
|
||||
|
||||
pub const ABS_MISC: u16 = 0x28;
|
||||
|
||||
pub const ABS_RESERVED: u16 = 0x2e;
|
||||
|
||||
pub const ABS_MT_SLOT: u16 = 0x2f;
|
||||
pub const ABS_MT_TOUCH_MAJOR: u16 = 0x30;
|
||||
pub const ABS_MT_TOUCH_MINOR: u16 = 0x31;
|
||||
pub const ABS_MT_WIDTH_MAJOR: u16 = 0x32;
|
||||
pub const ABS_MT_WIDTH_MINOR: u16 = 0x33;
|
||||
pub const ABS_MT_ORIENTATION: u16 = 0x34;
|
||||
pub const ABS_MT_POSITION_X: u16 = 0x35;
|
||||
pub const ABS_MT_POSITION_Y: u16 = 0x36;
|
||||
pub const ABS_MT_TOOL_TYPE: u16 = 0x37;
|
||||
pub const ABS_MT_BLOB_ID: u16 = 0x38;
|
||||
pub const ABS_MT_TRACKING_ID: u16 = 0x39;
|
||||
pub const ABS_MT_PRESSURE: u16 = 0x3a;
|
||||
pub const ABS_MT_DISTANCE: u16 = 0x3b;
|
||||
pub const ABS_MT_TOOL_X: u16 = 0x3c;
|
||||
pub const ABS_MT_TOOL_Y: u16 = 0x3d;
|
||||
|
||||
pub const ABS_MAX: u16 = 0x3f;
|
||||
pub const ABS_CNT: u16 = (ABS_MAX + 1);
|
||||
}
|
||||
|
||||
/// Switch events
|
||||
pub mod sw {
|
||||
pub const SW_LID: u16 = 0x00;
|
||||
pub const SW_TABLET_MODE: u16 = 0x01;
|
||||
pub const SW_HEADPHONE_INSERT: u16 = 0x02;
|
||||
pub const SW_RFKILL_ALL: u16 = 0x03;
|
||||
|
||||
pub const SW_RADIO: u16 = SW_RFKILL_ALL;
|
||||
pub const SW_MICROPHONE_INSERT: u16 = 0x04;
|
||||
pub const SW_DOCK: u16 = 0x05;
|
||||
pub const SW_LINEOUT_INSERT: u16 = 0x06;
|
||||
pub const SW_JACK_PHYSICAL_INSERT: u16 = 0x07;
|
||||
pub const SW_VIDEOOUT_INSERT: u16 = 0x08;
|
||||
pub const SW_CAMERA_LENS_COVER: u16 = 0x09;
|
||||
pub const SW_KEYPAD_SLIDE: u16 = 0x0a;
|
||||
pub const SW_FRONT_PROXIMITY: u16 = 0x0b;
|
||||
pub const SW_ROTATE_LOCK: u16 = 0x0c;
|
||||
pub const SW_LINEIN_INSERT: u16 = 0x0d;
|
||||
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);
|
||||
}
|
||||
|
||||
/// Misc events
|
||||
pub mod msc {
|
||||
pub const MSC_SERIAL: u16 = 0x00;
|
||||
pub const MSC_PULSELED: u16 = 0x01;
|
||||
pub const MSC_GESTURE: u16 = 0x02;
|
||||
pub const MSC_RAW: u16 = 0x03;
|
||||
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);
|
||||
}
|
||||
|
||||
/// LEDs
|
||||
pub mod led {
|
||||
pub const LED_NUML: u16 = 0x00;
|
||||
pub const LED_CAPSL: u16 = 0x01;
|
||||
pub const LED_SCROLLL: u16 = 0x02;
|
||||
pub const LED_COMPOSE: u16 = 0x03;
|
||||
pub const LED_KANA: u16 = 0x04;
|
||||
pub const LED_SLEEP: u16 = 0x05;
|
||||
pub const LED_SUSPEND: u16 = 0x06;
|
||||
pub const LED_MUTE: u16 = 0x07;
|
||||
pub const LED_MISC: u16 = 0x08;
|
||||
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);
|
||||
}
|
||||
|
||||
/// Autorepeat values
|
||||
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);
|
||||
}
|
||||
|
||||
/// Sounds
|
||||
pub mod snd {
|
||||
pub const SND_CLICK: u16 = 0x00;
|
||||
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);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
//! Only Mouse currently.
|
||||
|
||||
mod mouse;
|
||||
|
||||
pub mod input_event_codes;
|
||||
|
||||
pub use mouse::{Mouse, MouseFlags, MouseState};
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
use alloc::{boxed::Box, sync::Arc};
|
||||
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::prelude::{CapabilityType, InputEvent, InputEventType};
|
||||
use crate::scheme::{impl_event_scheme, InputScheme};
|
||||
use crate::utils::EventListener;
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct MouseFlags: u8 {
|
||||
/// Whether or not the left mouse button is pressed.
|
||||
const LEFT_BTN = 1 << 0;
|
||||
/// Whether or not the right mouse button is pressed.
|
||||
const RIGHT_BTN = 1 << 1;
|
||||
/// Whether or not the middle mouse button is pressed.
|
||||
const MIDDLE_BTN = 1 << 2;
|
||||
/// Whether or not the packet is valid or not.
|
||||
const ALWAYS_ONE = 1 << 3;
|
||||
/// Whether or not the x delta is negative.
|
||||
const X_SIGN = 1 << 4;
|
||||
/// Whether or not the y delta is negative.
|
||||
const Y_SIGN = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub struct MouseState {
|
||||
pub dx: i32,
|
||||
pub dy: i32,
|
||||
pub dz: i32,
|
||||
pub buttons: MouseFlags,
|
||||
}
|
||||
|
||||
impl MouseState {
|
||||
pub fn as_ps2_buf(&self) -> [u8; 3] {
|
||||
let mut flags = self.buttons | MouseFlags::ALWAYS_ONE;
|
||||
let dx = self.dx.max(-127).min(127);
|
||||
let dy = self.dy.max(-127).min(127);
|
||||
if dx < 0 {
|
||||
flags |= MouseFlags::X_SIGN;
|
||||
}
|
||||
if dy < 0 {
|
||||
flags |= MouseFlags::Y_SIGN;
|
||||
}
|
||||
[flags.bits(), dx as u8, dy as u8]
|
||||
}
|
||||
}
|
||||
|
||||
impl MouseState {
|
||||
fn update(&mut self, e: &InputEvent) -> Option<MouseState> {
|
||||
match e.event_type {
|
||||
InputEventType::Syn => {
|
||||
use super::input_event_codes::syn::*;
|
||||
if e.code == SYN_REPORT {
|
||||
let saved = *self;
|
||||
self.dx = 0;
|
||||
self.dy = 0;
|
||||
self.dz = 0;
|
||||
return Some(saved);
|
||||
}
|
||||
}
|
||||
InputEventType::Key => {
|
||||
use super::input_event_codes::key::*;
|
||||
let btn = match e.code {
|
||||
BTN_LEFT => MouseFlags::LEFT_BTN,
|
||||
BTN_RIGHT => MouseFlags::RIGHT_BTN,
|
||||
BTN_MIDDLE => MouseFlags::MIDDLE_BTN,
|
||||
_ => return None,
|
||||
};
|
||||
if e.value == 0 {
|
||||
self.buttons -= btn;
|
||||
} else {
|
||||
self.buttons |= btn;
|
||||
}
|
||||
}
|
||||
InputEventType::RelAxis => {
|
||||
use super::input_event_codes::rel::*;
|
||||
match e.code {
|
||||
REL_X => self.dx += e.value,
|
||||
REL_Y => self.dy -= e.value,
|
||||
REL_WHEEL => self.dz -= e.value,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mouse {
|
||||
listener: EventListener<MouseState>,
|
||||
state: Mutex<MouseState>,
|
||||
}
|
||||
|
||||
impl_event_scheme!(Mouse, MouseState);
|
||||
|
||||
impl Mouse {
|
||||
pub fn new(input: Arc<dyn InputScheme>) -> Arc<Self> {
|
||||
let ret = Arc::new(Self {
|
||||
listener: EventListener::new(),
|
||||
state: Mutex::new(MouseState::default()),
|
||||
});
|
||||
let cloned = ret.clone();
|
||||
input.subscribe(Box::new(move |e| cloned.handle_input_event(e)), false);
|
||||
ret
|
||||
}
|
||||
|
||||
fn handle_input_event(&self, e: &InputEvent) {
|
||||
if let Some(p) = self.state.lock().update(e) {
|
||||
self.listener.trigger(p);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compatible_with(input: &Arc<dyn InputScheme>) -> bool {
|
||||
// A mouse like device, at least one button, two relative axes.
|
||||
use super::input_event_codes::{ev::*, key::*, rel::*};
|
||||
let ev = input.capability(CapabilityType::Event);
|
||||
let key = input.capability(CapabilityType::Key);
|
||||
let rel = input.capability(CapabilityType::RelAxis);
|
||||
if !ev.contains_all(&[EV_KEY, EV_REL]) {
|
||||
return false;
|
||||
}
|
||||
if !key.contains(BTN_LEFT) {
|
||||
return false;
|
||||
}
|
||||
if !rel.contains_all(&[REL_X, REL_Y]) {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
use super::Io;
|
||||
use core::ops::{BitAnd, BitOr, Not};
|
||||
|
||||
// 主存映射 I/O。
|
||||
/// Memory-mapped I/O.
|
||||
#[repr(transparent)]
|
||||
pub struct Mmio<T>(T);
|
||||
|
||||
impl<T> Mmio<T> {
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because `base_addr` may be an arbitrary address.
|
||||
pub unsafe fn from_base_as<'a, R>(base_addr: usize) -> &'a mut R {
|
||||
assert_eq!(base_addr % core::mem::size_of::<T>(), 0);
|
||||
&mut *(base_addr as *mut R)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because `base_addr` may be an arbitrary address.
|
||||
pub unsafe fn from_base<'a>(base_addr: usize) -> &'a mut Self {
|
||||
Self::from_base_as(base_addr)
|
||||
}
|
||||
|
||||
pub fn add<'a>(&self, offset: usize) -> &'a mut Self {
|
||||
unsafe { Self::from_base((&self.0 as *const T).add(offset) as _) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Io for Mmio<T>
|
||||
where
|
||||
T: Copy + BitAnd<Output = T> + BitOr<Output = T> + Not<Output = T>,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn read(&self) -> T {
|
||||
#[allow(clippy::let_and_return)]
|
||||
unsafe {
|
||||
let val = core::ptr::read_volatile(&self.0 as *const _);
|
||||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
core::arch::asm!("fence i,r");
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, value: T) {
|
||||
unsafe {
|
||||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
core::arch::asm!("fence w,o");
|
||||
core::ptr::write_volatile(&mut self.0 as *mut _, value)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
// 封装对外设地址空间的访问,包括内存映射 IO 和端口映射 IO。
|
||||
//
|
||||
// 要了解这两种访问外设的方式,查看[维基百科](https://en.wikipedia.org/wiki/Memory-mapped_I/O)。
|
||||
//! Peripheral address space access, including memory-mapped IO and port-mapped IO.
|
||||
//!
|
||||
//! About these two methods of performing I/O, see [wikipedia](https://en.wikipedia.org/wiki/Memory-mapped_I/O).
|
||||
|
||||
use core::ops::{BitAnd, BitOr, Not};
|
||||
|
||||
mod mmio;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod pmio;
|
||||
|
||||
pub use mmio::Mmio;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use pmio::Pmio;
|
||||
|
||||
// 用于处理外设地址空间访问的接口。
|
||||
/// An interface for dealing with device address space access.
|
||||
pub trait Io {
|
||||
// 可访问的对象的类型。
|
||||
/// The type of object to access.
|
||||
type Value: Copy
|
||||
+ BitAnd<Output = Self::Value>
|
||||
+ BitOr<Output = Self::Value>
|
||||
+ Not<Output = Self::Value>;
|
||||
|
||||
// 从外设读取值。
|
||||
/// Reads value from device.
|
||||
fn read(&self) -> Self::Value;
|
||||
|
||||
// 向外设写入值。
|
||||
/// Writes `value` to device.
|
||||
fn write(&mut self, value: Self::Value);
|
||||
}
|
||||
|
||||
// 外设地址空间的一个只读单元。
|
||||
/// A readonly unit in device address space.
|
||||
#[repr(transparent)]
|
||||
pub struct ReadOnly<I>(I);
|
||||
|
||||
impl<I> ReadOnly<I> {
|
||||
// 构造外设地址空间的一个只读单元。
|
||||
/// Constructs a readonly unit in device address space.
|
||||
pub const fn new(inner: I) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Io> ReadOnly<I> {
|
||||
// 从外设读取值。
|
||||
/// Reads value from device.
|
||||
#[inline(always)]
|
||||
pub fn read(&self) -> I::Value {
|
||||
self.0.read()
|
||||
}
|
||||
}
|
||||
|
||||
// 外设地址空间的一个只写单元。
|
||||
/// A write-only unit in device address space.
|
||||
#[repr(transparent)]
|
||||
pub struct WriteOnly<I>(I);
|
||||
|
||||
impl<I> WriteOnly<I> {
|
||||
// 构造外设地址空间的一个只写单元。
|
||||
/// Constructs a write-only unit in device address space.
|
||||
pub const fn new(inner: I) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Io> WriteOnly<I> {
|
||||
// 向外设写入值。
|
||||
/// Writes `value` to device.
|
||||
#[inline(always)]
|
||||
pub fn write(&mut self, value: I::Value) {
|
||||
self.0.write(value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
// 端口映射 I/O。
|
||||
//! Port-mapped I/O.
|
||||
|
||||
use super::Io;
|
||||
use core::{arch::asm, marker::PhantomData};
|
||||
|
||||
// 端口映射 I/O。
|
||||
/// Port-mapped I/O.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Pmio<T> {
|
||||
port: u16,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Pmio<T> {
|
||||
// 映射指定端口进行外设访问。
|
||||
/// Maps a given port to assess device.
|
||||
pub const fn new(port: u16) -> Self {
|
||||
Self {
|
||||
port,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 逐字节端口映射读写。
|
||||
/// Read/Write for byte PMIO.
|
||||
impl Io for Pmio<u8> {
|
||||
type Value = u8;
|
||||
|
||||
// 读。
|
||||
/// Read.
|
||||
#[inline(always)]
|
||||
fn read(&self) -> u8 {
|
||||
let value: u8;
|
||||
unsafe {
|
||||
asm!("in al, dx", out("al") value, in("dx") self.port, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
// 写。
|
||||
/// Write.
|
||||
#[inline(always)]
|
||||
fn write(&mut self, value: u8) {
|
||||
unsafe {
|
||||
asm!("out dx, al", in("al") value, in("dx") self.port, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 逐字端口映射读写。
|
||||
/// Read/Write for word PMIO.
|
||||
impl Io for Pmio<u16> {
|
||||
type Value = u16;
|
||||
|
||||
// 读。
|
||||
/// Read.
|
||||
#[inline(always)]
|
||||
fn read(&self) -> u16 {
|
||||
let value: u16;
|
||||
unsafe {
|
||||
asm!("in ax, dx", out("ax") value, in("dx") self.port, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
// 写。
|
||||
/// Write.
|
||||
#[inline(always)]
|
||||
fn write(&mut self, value: u16) {
|
||||
unsafe {
|
||||
asm!("out dx, ax", in("ax") value, in("dx") self.port, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 逐双字端口映射读写。
|
||||
/// Read/Write for double-word PMIO.
|
||||
impl Io for Pmio<u32> {
|
||||
type Value = u32;
|
||||
|
||||
// 读。
|
||||
/// Read.
|
||||
#[inline(always)]
|
||||
fn read(&self) -> u32 {
|
||||
let value: u32;
|
||||
unsafe {
|
||||
asm!("in eax, dx", out("eax") value, in("dx") self.port, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
// 写。
|
||||
/// Write.
|
||||
#[inline(always)]
|
||||
fn write(&mut self, value: u32) {
|
||||
unsafe {
|
||||
asm!("out dx, eax", in("eax") value, in("dx") self.port, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
//! External interrupt request and handle.
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
|
||||
mod riscv_intc;
|
||||
mod riscv_plic;
|
||||
|
||||
/// Implementation of risc-v interrupt controller.
|
||||
#[doc(cfg(any(target_arch = "riscv32", target_arch = "riscv64")))]
|
||||
pub mod riscv {
|
||||
pub use super::riscv_intc::{Intc, ScauseIntCode};
|
||||
pub use super::riscv_plic::Plic;
|
||||
}
|
||||
} else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
|
||||
mod x86_apic;
|
||||
/// Implementation of x86 Advanced Programmable Interrupt Controller.
|
||||
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
pub mod x86 {
|
||||
pub use super::x86_apic::Apic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
use lock::Mutex;
|
||||
use riscv::register::sie;
|
||||
|
||||
use crate::prelude::IrqHandler;
|
||||
use crate::scheme::{IrqScheme, Scheme};
|
||||
use crate::{DeviceError, DeviceResult};
|
||||
use alloc::format;
|
||||
use alloc::string::String;
|
||||
use core::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
const S_SOFT: usize = 1;
|
||||
const S_TIMER: usize = 5;
|
||||
const S_EXT: usize = 9;
|
||||
|
||||
static INTC_NUM: AtomicU8 = AtomicU8::new(0);
|
||||
|
||||
#[repr(usize)]
|
||||
pub enum ScauseIntCode {
|
||||
SupervisorSoft = S_SOFT,
|
||||
SupervisorTimer = S_TIMER,
|
||||
SupervisorExternal = S_EXT,
|
||||
}
|
||||
|
||||
pub struct Intc {
|
||||
name: String,
|
||||
soft_handler: Mutex<Option<IrqHandler>>,
|
||||
timer_handler: Mutex<Option<IrqHandler>>,
|
||||
ext_handler: Mutex<Option<IrqHandler>>,
|
||||
}
|
||||
|
||||
impl Intc {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name: format!("riscv-intc-cpu{}", INTC_NUM.fetch_add(1, Ordering::Relaxed)),
|
||||
soft_handler: Mutex::new(None),
|
||||
timer_handler: Mutex::new(None),
|
||||
ext_handler: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_handler<F>(&self, cause: usize, op: F) -> DeviceResult
|
||||
where
|
||||
F: FnOnce(&mut Option<IrqHandler>) -> DeviceResult,
|
||||
{
|
||||
match cause {
|
||||
S_SOFT => op(&mut self.soft_handler.lock()),
|
||||
S_TIMER => op(&mut self.timer_handler.lock()),
|
||||
S_EXT => op(&mut self.ext_handler.lock()),
|
||||
_ => {
|
||||
error!("invalid SCAUSE value {:#x}!", cause);
|
||||
Err(DeviceError::InvalidParam)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Intc {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheme for Intc {
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
fn handle_irq(&self, cause: usize) {
|
||||
self.with_handler(cause, |opt| {
|
||||
if let Some(h) = opt {
|
||||
h();
|
||||
} else {
|
||||
warn!("no registered handler for SCAUSE {}!", cause);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl IrqScheme for Intc {
|
||||
fn is_valid_irq(&self, cause: usize) -> bool {
|
||||
matches!(cause, S_SOFT | S_TIMER | S_EXT)
|
||||
}
|
||||
|
||||
fn mask(&self, cause: usize) -> DeviceResult {
|
||||
unsafe {
|
||||
match cause {
|
||||
S_SOFT => sie::clear_ssoft(),
|
||||
S_TIMER => sie::clear_stimer(),
|
||||
S_EXT => sie::clear_sext(),
|
||||
_ => return Err(DeviceError::InvalidParam),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unmask(&self, cause: usize) -> DeviceResult {
|
||||
unsafe {
|
||||
match cause {
|
||||
S_SOFT => sie::set_ssoft(),
|
||||
S_TIMER => sie::set_stimer(),
|
||||
S_EXT => sie::set_sext(),
|
||||
_ => return Err(DeviceError::InvalidParam),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_handler(&self, cause: usize, handler: IrqHandler) -> DeviceResult {
|
||||
self.with_handler(cause, |opt| {
|
||||
if opt.is_some() {
|
||||
Err(DeviceError::AlreadyExists)
|
||||
} else {
|
||||
*opt = Some(handler);
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn unregister(&self, cause: usize) -> DeviceResult {
|
||||
self.with_handler(cause, |opt| {
|
||||
if opt.is_some() {
|
||||
*opt = None;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(DeviceError::InvalidParam)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
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};
|
||||
|
||||
const IRQ_RANGE: Range<usize> = 1..1024;
|
||||
|
||||
const PLIC_PRIORITY_BASE: usize = 0x0;
|
||||
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>();
|
||||
|
||||
const PLIC_ENABLE_HART_OFFSET: usize = 0x100 / core::mem::size_of::<u32>();
|
||||
const PLIC_PRIORITY_HART_OFFSET: usize = 0x2000 / core::mem::size_of::<u32>();
|
||||
const PLIC_CONTEXT_CLAIM_HART_OFFSET: usize = 0x2000 / core::mem::size_of::<u32>();
|
||||
|
||||
struct PlicUnlocked {
|
||||
priority_base: &'static mut Mmio<u32>,
|
||||
enable_base: &'static mut Mmio<u32>,
|
||||
context_base: &'static mut Mmio<u32>,
|
||||
manager: IrqManager<1024>,
|
||||
}
|
||||
|
||||
pub struct Plic {
|
||||
inner: Mutex<PlicUnlocked>,
|
||||
}
|
||||
|
||||
impl PlicUnlocked {
|
||||
/// Toggle irq enable on the current hart.
|
||||
fn toggle(&mut self, irq_num: usize, enable: bool) {
|
||||
debug_assert!(IRQ_RANGE.contains(&irq_num));
|
||||
let hart_id = cpu_id() as usize;
|
||||
let mmio = self
|
||||
.enable_base
|
||||
.add(PLIC_ENABLE_HART_OFFSET * hart_id + irq_num / 32);
|
||||
|
||||
let mask = 1 << (irq_num % 32);
|
||||
if enable {
|
||||
mmio.write(mmio.read() | mask);
|
||||
} else {
|
||||
mmio.write(mmio.read() & !mask);
|
||||
}
|
||||
}
|
||||
|
||||
/// Ask the PLIC what type of interrupt is occurred on the current hart.
|
||||
fn pending_irq(&mut self) -> Option<usize> {
|
||||
let hart_id = cpu_id() as usize;
|
||||
let irq_num = self
|
||||
.context_base
|
||||
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id + PLIC_CONTEXT_CLAIM)
|
||||
.read() as usize;
|
||||
if irq_num == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(irq_num)
|
||||
}
|
||||
}
|
||||
|
||||
/// Tell the PLIC we've served this IRQ.
|
||||
fn eoi(&mut self, irq_num: usize) {
|
||||
debug_assert!(IRQ_RANGE.contains(&irq_num));
|
||||
let hart_id = cpu_id() as usize;
|
||||
self.context_base
|
||||
.add(PLIC_CONTEXT_CLAIM + PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
|
||||
.write(irq_num as _);
|
||||
}
|
||||
|
||||
/// Set the priority for the irq_num.
|
||||
fn set_priority(&mut self, irq_num: usize, priority: u8) {
|
||||
debug_assert!(IRQ_RANGE.contains(&irq_num));
|
||||
self.priority_base.add(irq_num).write(priority as _);
|
||||
}
|
||||
|
||||
/// Set current hart's priority threshold to 0.
|
||||
fn set_threshold(&mut self, threshold: u8) {
|
||||
let hart_id = cpu_id() as usize;
|
||||
self.context_base
|
||||
.add(PLIC_PRIORITY_HART_OFFSET * hart_id + PLIC_CONTEXT_THRESHOLD)
|
||||
.write(threshold as _);
|
||||
}
|
||||
|
||||
fn init_hart(&mut self) {
|
||||
self.set_threshold(0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Plic {
|
||||
pub fn new(base: usize) -> Self {
|
||||
let mut inner = PlicUnlocked {
|
||||
priority_base: unsafe { Mmio::<u32>::from_base(base + PLIC_PRIORITY_BASE) },
|
||||
enable_base: unsafe { Mmio::<u32>::from_base(base + PLIC_ENABLE_BASE) },
|
||||
context_base: unsafe { Mmio::<u32>::from_base(base + PLIC_CONTEXT_BASE) },
|
||||
manager: IrqManager::new(IRQ_RANGE),
|
||||
};
|
||||
inner.init_hart();
|
||||
Self {
|
||||
inner: Mutex::new(inner),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheme for Plic {
|
||||
fn name(&self) -> &str {
|
||||
"riscv-plic"
|
||||
}
|
||||
|
||||
fn handle_irq(&self, _unused: usize) {
|
||||
let mut inner = self.inner.lock();
|
||||
while let Some(irq_num) = inner.pending_irq() {
|
||||
if inner.manager.handle(irq_num).is_err() {
|
||||
warn!("no registered handler for IRQ {}!", irq_num);
|
||||
}
|
||||
trace!("riscv plic handle irq: {}", irq_num);
|
||||
inner.eoi(irq_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IrqScheme for Plic {
|
||||
fn is_valid_irq(&self, irq_num: usize) -> bool {
|
||||
IRQ_RANGE.contains(&irq_num)
|
||||
}
|
||||
|
||||
fn mask(&self, irq_num: usize) -> DeviceResult {
|
||||
if self.is_valid_irq(irq_num) {
|
||||
self.inner.lock().toggle(irq_num, false);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(DeviceError::InvalidParam)
|
||||
}
|
||||
}
|
||||
|
||||
fn unmask(&self, irq_num: usize) -> DeviceResult {
|
||||
if self.is_valid_irq(irq_num) {
|
||||
self.inner.lock().toggle(irq_num, true);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(DeviceError::InvalidParam)
|
||||
}
|
||||
}
|
||||
|
||||
fn register_handler(&self, irq_num: usize, handler: IrqHandler) -> DeviceResult {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.manager.register_handler(irq_num, handler).map(|_| {
|
||||
inner.set_priority(irq_num, 7);
|
||||
})
|
||||
}
|
||||
|
||||
fn unregister(&self, irq_num: usize) -> DeviceResult {
|
||||
self.inner.lock().manager.unregister_handler(irq_num)
|
||||
}
|
||||
|
||||
fn init_hart(&self) {
|
||||
self.inner.lock().init_hart();
|
||||
}
|
||||
}
|
||||
|
||||
fn cpu_id() -> u8 {
|
||||
let mut cpu_id;
|
||||
unsafe {
|
||||
asm!("mv {0}, tp", out(reg) cpu_id);
|
||||
}
|
||||
cpu_id
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
// TODO: configurable
|
||||
|
||||
pub const X86_INT_BASE: usize = 0x20;
|
||||
|
||||
pub const X86_INT_LOCAL_APIC_BASE: usize = 0xf0;
|
||||
pub const X86_INT_APIC_SPURIOUS: usize = X86_INT_LOCAL_APIC_BASE;
|
||||
pub const X86_INT_APIC_TIMER: usize = X86_INT_LOCAL_APIC_BASE + 0x1;
|
||||
pub const X86_INT_APIC_ERROR: usize = X86_INT_LOCAL_APIC_BASE + 0x2;
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
use alloc::vec::Vec;
|
||||
use core::{fmt, ptr::NonNull};
|
||||
|
||||
use acpi::platform::interrupt::InterruptModel;
|
||||
use acpi::{AcpiHandler, AcpiTables, PhysicalMapping};
|
||||
use lock::Mutex;
|
||||
use x2apic::ioapic::{IoApic as IoApicInner, IrqFlags, IrqMode};
|
||||
|
||||
use super::{IrqPolarity, IrqTriggerMode, Phys2VirtFn};
|
||||
|
||||
const PAGE_SIZE: usize = 4096;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AcpiMapHandler {
|
||||
phys_to_virt: Phys2VirtFn,
|
||||
}
|
||||
|
||||
impl AcpiHandler for AcpiMapHandler {
|
||||
/// we just impl this function, `rdsp` crate will use it, and we not.
|
||||
unsafe fn map_physical_region<T>(
|
||||
&self,
|
||||
physical_address: usize,
|
||||
size: usize,
|
||||
) -> PhysicalMapping<Self, T> {
|
||||
// address maybe not aligned, so we align it mannualy
|
||||
let aligned_start = physical_address & !(PAGE_SIZE - 1);
|
||||
let aligned_end = (physical_address + size + PAGE_SIZE - 1) & !(PAGE_SIZE - 1);
|
||||
PhysicalMapping::new(
|
||||
physical_address,
|
||||
NonNull::new_unchecked((self.phys_to_virt)(physical_address) as *mut T),
|
||||
size,
|
||||
aligned_end - aligned_start,
|
||||
self.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
/// we do nothing here
|
||||
fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
|
||||
}
|
||||
|
||||
/// An I/O APIC structure.
|
||||
///
|
||||
/// For local APIC and I/O APIC, we can learn something from here: <https://wiki.osdev.org/APIC>.
|
||||
pub struct IoApic {
|
||||
/// I/O APIC id.
|
||||
id: u8,
|
||||
/// GSI means Global System Interrupt, `gsi_start` is the base number of GSI
|
||||
/// in this I/O APIC.
|
||||
gsi_start: u32,
|
||||
/// Max entry num of the interrupt redirection table.
|
||||
max_entry: u8,
|
||||
/// Use `x2apic` crate to help us manipulate IOAPIC.
|
||||
inner: Mutex<IoApicInner>,
|
||||
}
|
||||
|
||||
/// A list of I/O-APICs for systems have multiple I/O subsystems.
|
||||
#[derive(Debug)]
|
||||
pub struct IoApicList {
|
||||
io_apics: Vec<IoApic>,
|
||||
}
|
||||
|
||||
impl IoApic {
|
||||
/// Create a new [`IoApic`] from fields parsed from the ACPI table, and
|
||||
/// initialize it by disabling all interrupts.
|
||||
pub fn new(id: u8, base_vaddr: usize, gsi_start: u32) -> Self {
|
||||
let mut inner = unsafe { IoApicInner::new(base_vaddr as u64) };
|
||||
let max_entry = unsafe { inner.max_table_entry() };
|
||||
unsafe { assert_eq!(id, inner.id()) };
|
||||
|
||||
unsafe {
|
||||
inner.init(super::X86_INT_BASE as u8);
|
||||
}
|
||||
for i in 0..max_entry + 1 {
|
||||
unsafe {
|
||||
// disable all interrupts
|
||||
inner.disable_irq(i);
|
||||
|
||||
// Clean the redirection table
|
||||
let mut entry = inner.table_entry(i);
|
||||
entry.set_vector(0);
|
||||
entry.set_dest(0);
|
||||
entry.set_mode(IrqMode::Fixed);
|
||||
entry.set_flags(IrqFlags::MASKED);
|
||||
inner.set_table_entry(i, entry);
|
||||
}
|
||||
}
|
||||
Self {
|
||||
id,
|
||||
gsi_start,
|
||||
max_entry,
|
||||
inner: Mutex::new(inner),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set apic entry IRQ state by `gsi`.
|
||||
pub fn toggle(&self, gsi: u32, enabled: bool) {
|
||||
let idx = (gsi - self.gsi_start) as u8;
|
||||
unsafe {
|
||||
if enabled {
|
||||
self.inner.lock().enable_irq(idx);
|
||||
} else {
|
||||
self.inner.lock().disable_irq(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the IDT vector of the `gsi` from redirection table.
|
||||
pub fn get_vector(&self, gsi: u32) -> u8 {
|
||||
let idx = (gsi - self.gsi_start) as u8;
|
||||
unsafe { self.inner.lock().table_entry(idx).vector() }
|
||||
}
|
||||
|
||||
/// Set the IDT vector of the `gsi` in redirection table.
|
||||
pub fn map_vector(&self, gsi: u32, vector: u8) {
|
||||
let idx = (gsi - self.gsi_start) as u8;
|
||||
let mut inner = self.inner.lock();
|
||||
unsafe {
|
||||
let mut entry = inner.table_entry(idx);
|
||||
entry.set_vector(vector);
|
||||
inner.set_table_entry(idx, entry);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the interrupt triggle mode, polarity and other fields of the `gsi`
|
||||
/// in redirection table.
|
||||
pub fn configure(&self, gsi: u32, tm: IrqTriggerMode, pol: IrqPolarity, dest: u8, vector: u8) {
|
||||
let idx = (gsi - self.gsi_start) as u8;
|
||||
let mut inner = self.inner.lock();
|
||||
let mut entry = unsafe { inner.table_entry(idx) };
|
||||
entry.set_vector(vector);
|
||||
entry.set_mode(IrqMode::Fixed);
|
||||
entry.set_dest(dest);
|
||||
|
||||
let mut flags = IrqFlags::MASKED; // destination mode: physical
|
||||
if matches!(tm, IrqTriggerMode::Edge) {
|
||||
flags |= IrqFlags::LEVEL_TRIGGERED;
|
||||
}
|
||||
if matches!(pol, IrqPolarity::ActiveLow) {
|
||||
flags |= IrqFlags::LOW_ACTIVE;
|
||||
}
|
||||
entry.set_flags(flags);
|
||||
|
||||
unsafe { inner.set_table_entry(idx, entry) };
|
||||
}
|
||||
}
|
||||
|
||||
impl IoApicList {
|
||||
/// Probe all I/O APICs from the ACPI table represented by `acpi_rsdp`.
|
||||
pub fn new(acpi_rsdp: usize, phys_to_virt: Phys2VirtFn) -> Self {
|
||||
let handler = AcpiMapHandler { phys_to_virt };
|
||||
// parse ACPI table by the physical address of the RSDP.
|
||||
let tables = unsafe { AcpiTables::from_rsdp(handler, acpi_rsdp).unwrap() };
|
||||
let io_apics =
|
||||
if let InterruptModel::Apic(apic) = tables.platform_info().unwrap().interrupt_model {
|
||||
apic.io_apics
|
||||
.iter()
|
||||
.map(|i| {
|
||||
IoApic::new(
|
||||
i.id,
|
||||
phys_to_virt(i.address as usize),
|
||||
i.global_system_interrupt_base,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
// only legacy i8259 PIC is present
|
||||
Vec::new()
|
||||
};
|
||||
Self { io_apics }
|
||||
}
|
||||
|
||||
/// Get the corresponding I/O APIC of the `gsi`, each I/O-APIC have a range
|
||||
/// of GSI number.
|
||||
pub fn find(&self, gsi: u32) -> Option<&IoApic> {
|
||||
self.io_apics
|
||||
.iter()
|
||||
.find(|i| i.gsi_start <= gsi && gsi <= i.gsi_start + i.max_entry as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for IoApic {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
struct RedirTable<'a>(&'a IoApic);
|
||||
|
||||
impl<'a> fmt::Debug for RedirTable<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut inner = self.0.inner.lock();
|
||||
let count = self.0.max_entry + 1;
|
||||
f.debug_list()
|
||||
.entries((0..count).map(|i| unsafe { inner.table_entry(i) }))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
let version = unsafe { self.inner.lock().version() };
|
||||
f.debug_struct("IoApic")
|
||||
.field("id", &self.id)
|
||||
.field("version", &version)
|
||||
.field("gsi_start", &self.gsi_start)
|
||||
.field("max_entry", &self.max_entry)
|
||||
.field("redir_table", &RedirTable(self))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
use x2apic::lapic::{
|
||||
xapic_base, LocalApic as LocalApicInner, LocalApicBuilder, TimerDivide, TimerMode,
|
||||
};
|
||||
|
||||
use super::{consts, Phys2VirtFn};
|
||||
|
||||
static mut LOCAL_APIC: Option<LocalApic> = None;
|
||||
static mut BSP_ID: Option<u8> = None;
|
||||
|
||||
pub struct LocalApic {
|
||||
inner: LocalApicInner,
|
||||
}
|
||||
|
||||
impl LocalApic {
|
||||
pub unsafe fn get<'a>() -> &'a mut LocalApic {
|
||||
LOCAL_APIC
|
||||
.as_mut()
|
||||
.expect("Local APIC is not initialized by BSP")
|
||||
}
|
||||
|
||||
pub unsafe fn init_bsp(phys_to_virt: Phys2VirtFn) {
|
||||
let base_vaddr = phys_to_virt(xapic_base() as usize);
|
||||
let mut inner = LocalApicBuilder::new()
|
||||
.timer_vector(consts::X86_INT_APIC_TIMER)
|
||||
.error_vector(consts::X86_INT_APIC_ERROR)
|
||||
.spurious_vector(consts::X86_INT_APIC_SPURIOUS)
|
||||
.set_xapic_base(base_vaddr as u64)
|
||||
.build()
|
||||
.unwrap_or_else(|err| panic!("{}", err));
|
||||
inner.enable();
|
||||
|
||||
assert!(inner.is_bsp());
|
||||
BSP_ID = Some((inner.id() >> 24) as u8);
|
||||
LOCAL_APIC = Some(LocalApic { inner });
|
||||
}
|
||||
|
||||
pub unsafe fn init_ap() {
|
||||
Self::get().inner.enable();
|
||||
}
|
||||
|
||||
pub fn bsp_id() -> u8 {
|
||||
unsafe { BSP_ID.unwrap() }
|
||||
}
|
||||
|
||||
pub fn id(&mut self) -> u8 {
|
||||
unsafe { (self.inner.id() >> 24) as u8 }
|
||||
}
|
||||
|
||||
pub fn eoi(&mut self) {
|
||||
unsafe { self.inner.end_of_interrupt() }
|
||||
}
|
||||
|
||||
pub fn disable_timer(&mut self) {
|
||||
unsafe { self.inner.disable_timer() }
|
||||
}
|
||||
|
||||
pub fn enable_timer(&mut self) {
|
||||
unsafe { self.inner.enable_timer() }
|
||||
}
|
||||
|
||||
pub fn set_timer_mode(&mut self, mode: TimerMode) {
|
||||
unsafe { self.inner.set_timer_mode(mode) }
|
||||
}
|
||||
|
||||
pub fn set_timer_divide(&mut self, divide: TimerDivide) {
|
||||
unsafe { self.inner.set_timer_divide(divide) }
|
||||
}
|
||||
|
||||
pub fn set_timer_initial(&mut self, initial: u32) {
|
||||
unsafe { self.inner.set_timer_initial(initial) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
mod consts;
|
||||
mod ioapic;
|
||||
mod lapic;
|
||||
|
||||
use self::consts::{X86_INT_BASE, X86_INT_LOCAL_APIC_BASE};
|
||||
use self::ioapic::{IoApic, IoApicList};
|
||||
use self::lapic::LocalApic;
|
||||
use crate::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
|
||||
use crate::scheme::{IrqScheme, Scheme};
|
||||
use crate::{utils::IrqManager, DeviceError, DeviceResult, PhysAddr, VirtAddr};
|
||||
use core::ops::Range;
|
||||
use lock::Mutex;
|
||||
|
||||
const IOAPIC_IRQ_RANGE: Range<usize> = X86_INT_BASE..X86_INT_LOCAL_APIC_BASE;
|
||||
const LAPIC_IRQ_RANGE: Range<usize> = 0..16;
|
||||
|
||||
type Phys2VirtFn = fn(paddr: PhysAddr) -> VirtAddr;
|
||||
|
||||
/// Advanced Programmable Interrupt Controller
|
||||
pub struct Apic {
|
||||
ioapic_list: IoApicList,
|
||||
manager_ioapic: Mutex<IrqManager<256>>,
|
||||
manager_lapic: Mutex<IrqManager<16>>,
|
||||
}
|
||||
|
||||
impl Apic {
|
||||
/// Construct a new `Apic`.
|
||||
pub fn new(acpi_rsdp: usize, phys_to_virt: Phys2VirtFn) -> Self {
|
||||
Self {
|
||||
ioapic_list: IoApicList::new(acpi_rsdp, phys_to_virt),
|
||||
manager_ioapic: Mutex::new(IrqManager::new(IOAPIC_IRQ_RANGE)),
|
||||
manager_lapic: Mutex::new(IrqManager::new(LAPIC_IRQ_RANGE)),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_ioapic<F>(&self, gsi: u32, op: F) -> DeviceResult
|
||||
where
|
||||
F: FnOnce(&IoApic) -> DeviceResult,
|
||||
{
|
||||
if let Some(apic) = self.ioapic_list.find(gsi) {
|
||||
op(apic)
|
||||
} else {
|
||||
error!(
|
||||
"cannot find IOAPIC for global system interrupt number {}",
|
||||
gsi
|
||||
);
|
||||
Err(DeviceError::InvalidParam)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_local_apic_bsp(phys_to_virt: Phys2VirtFn) {
|
||||
unsafe { LocalApic::init_bsp(phys_to_virt) }
|
||||
}
|
||||
|
||||
pub fn init_local_apic_ap() {
|
||||
unsafe { LocalApic::init_ap() }
|
||||
}
|
||||
|
||||
pub fn local_apic<'a>() -> &'a mut LocalApic {
|
||||
unsafe { LocalApic::get() }
|
||||
}
|
||||
|
||||
pub fn register_local_apic_handler(&self, vector: usize, handler: IrqHandler) -> DeviceResult {
|
||||
if vector >= X86_INT_LOCAL_APIC_BASE {
|
||||
self.manager_lapic
|
||||
.lock()
|
||||
.register_handler(vector - X86_INT_LOCAL_APIC_BASE, handler)?;
|
||||
Ok(())
|
||||
} else {
|
||||
error!("invalid local APIC interrupt vector {}", vector);
|
||||
Err(DeviceError::InvalidParam)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheme for Apic {
|
||||
fn name(&self) -> &str {
|
||||
"x86-apic"
|
||||
}
|
||||
|
||||
fn handle_irq(&self, vector: usize) {
|
||||
Self::local_apic().eoi();
|
||||
let res = if vector >= X86_INT_LOCAL_APIC_BASE {
|
||||
let handler = self.manager_lapic.lock();
|
||||
handler.handle(vector - X86_INT_LOCAL_APIC_BASE)
|
||||
} else {
|
||||
self.manager_ioapic.lock().handle(vector)
|
||||
};
|
||||
if res.is_err() {
|
||||
warn!("no registered handler for interrupt vector {}!", vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IrqScheme for Apic {
|
||||
fn is_valid_irq(&self, gsi: usize) -> bool {
|
||||
self.ioapic_list.find(gsi as _).is_some()
|
||||
}
|
||||
|
||||
fn mask(&self, gsi: usize) -> DeviceResult {
|
||||
self.with_ioapic(gsi as _, |apic| {
|
||||
apic.toggle(gsi as _, false);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn unmask(&self, gsi: usize) -> DeviceResult {
|
||||
self.with_ioapic(gsi as _, |apic| {
|
||||
apic.toggle(gsi as _, true);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn configure(&self, gsi: usize, tm: IrqTriggerMode, pol: IrqPolarity) -> DeviceResult {
|
||||
let gsi = gsi as u32;
|
||||
self.with_ioapic(gsi, |apic| {
|
||||
apic.configure(gsi, tm, pol, LocalApic::bsp_id(), 0);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn register_handler(&self, gsi: usize, handler: IrqHandler) -> DeviceResult {
|
||||
let gsi = gsi as u32;
|
||||
self.with_ioapic(gsi, |apic| {
|
||||
let vector = apic.get_vector(gsi) as _; // if not mapped, allocate an available vector by `register_handler()`.
|
||||
let vector = self
|
||||
.manager_ioapic
|
||||
.lock()
|
||||
.register_handler(vector, handler)? as u8;
|
||||
apic.map_vector(gsi, vector);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn unregister(&self, gsi: usize) -> DeviceResult {
|
||||
let gsi = gsi as u32;
|
||||
self.with_ioapic(gsi, |apic| {
|
||||
let vector = apic.get_vector(gsi) as _;
|
||||
self.manager_ioapic.lock().unregister_handler(vector)?;
|
||||
apic.map_vector(gsi, 0);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn msi_alloc_block(&self, requested_irqs: usize) -> DeviceResult<Range<usize>> {
|
||||
let alloc_size = requested_irqs.next_power_of_two();
|
||||
let start = self.manager_ioapic.lock().alloc_block(alloc_size)?;
|
||||
Ok(start..start + alloc_size)
|
||||
}
|
||||
|
||||
fn msi_free_block(&self, block: Range<usize>) -> DeviceResult {
|
||||
self.manager_lapic
|
||||
.lock()
|
||||
.free_block(block.start, block.len())
|
||||
}
|
||||
|
||||
fn msi_register_handler(
|
||||
&self,
|
||||
block: Range<usize>,
|
||||
msi_id: usize,
|
||||
handler: IrqHandler,
|
||||
) -> DeviceResult {
|
||||
if msi_id < block.len() {
|
||||
self.manager_ioapic
|
||||
.lock()
|
||||
.overwrite_handler(block.start + msi_id, handler)
|
||||
} else {
|
||||
Err(DeviceError::InvalidParam)
|
||||
}
|
||||
}
|
||||
|
||||
fn apic_timer_enable(&self) {
|
||||
// SAFETY: this will called only once for every core
|
||||
Apic::local_apic().enable_timer();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
//! Device drivers of zCore.
|
||||
|
||||
#![cfg_attr(not(feature = "mock"), no_std)]
|
||||
#![feature(doc_cfg)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use core::fmt;
|
||||
|
||||
#[cfg(any(feature = "mock", doc))]
|
||||
#[doc(cfg(feature = "mock"))]
|
||||
pub mod mock;
|
||||
|
||||
#[cfg(any(feature = "virtio", doc))]
|
||||
#[doc(cfg(feature = "virtio"))]
|
||||
pub mod virtio;
|
||||
|
||||
pub mod builder;
|
||||
pub mod bus;
|
||||
pub mod display;
|
||||
pub mod input;
|
||||
pub mod io;
|
||||
pub mod irq;
|
||||
pub mod net;
|
||||
pub mod prelude;
|
||||
pub mod scheme;
|
||||
pub mod uart;
|
||||
pub mod utils;
|
||||
|
||||
/// The error type for external device.
|
||||
#[derive(Debug)]
|
||||
pub enum DeviceError {
|
||||
/// The buffer is too small.
|
||||
BufferTooSmall,
|
||||
/// The device is not ready.
|
||||
NotReady,
|
||||
/// Invalid parameter.
|
||||
InvalidParam,
|
||||
/// Failed to alloc DMA memory.
|
||||
DmaError,
|
||||
/// I/O Error
|
||||
IoError,
|
||||
/// A resource with the specified identifier already exists.
|
||||
AlreadyExists,
|
||||
/// No resource to allocate.
|
||||
NoResources,
|
||||
/// The device driver is not implemented, supported, or enabled.
|
||||
NotSupported,
|
||||
}
|
||||
|
||||
/// A type alias for the result of a device operation.
|
||||
pub type DeviceResult<T = ()> = core::result::Result<T, DeviceError>;
|
||||
|
||||
/// Static shell of shared dynamic device [`Scheme`](crate::scheme::Scheme) types.
|
||||
#[derive(Clone)]
|
||||
pub enum Device {
|
||||
/// Block device
|
||||
Block(Arc<dyn scheme::BlockScheme>),
|
||||
/// Display device
|
||||
Display(Arc<dyn scheme::DisplayScheme>),
|
||||
/// Input device
|
||||
Input(Arc<dyn scheme::InputScheme>),
|
||||
/// Interrupt request and handle
|
||||
Irq(Arc<dyn scheme::IrqScheme>),
|
||||
/// Network device
|
||||
Net(Arc<dyn scheme::NetScheme>),
|
||||
/// Uart port
|
||||
Uart(Arc<dyn scheme::UartScheme>),
|
||||
}
|
||||
|
||||
impl Device {
|
||||
/// Get a general [`Scheme`](scheme::Scheme) from the device.
|
||||
pub fn inner(&self) -> Arc<dyn scheme::Scheme> {
|
||||
match self {
|
||||
Self::Block(d) => d.clone().upcast(),
|
||||
Self::Display(d) => d.clone().upcast(),
|
||||
Self::Input(d) => d.clone().upcast(),
|
||||
Self::Irq(d) => d.clone().upcast(),
|
||||
Self::Net(d) => d.clone().upcast(),
|
||||
Self::Uart(d) => d.clone().upcast(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Device {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Block(d) => write!(f, "BlockDevice({:?})", d.name()),
|
||||
Self::Display(d) => write!(f, "DisplayDevice({:?})", d.name()),
|
||||
Self::Input(d) => write!(f, "InputDevice({:?})", d.name()),
|
||||
Self::Irq(d) => write!(f, "IrqDevice({:?})", d.name()),
|
||||
Self::Net(d) => write!(f, "NetDevice({:?})", d.name()),
|
||||
Self::Uart(d) => write!(f, "UartDevice({:?})", d.name()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type PhysAddr = usize;
|
||||
type VirtAddr = usize;
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
use alloc::vec::Vec;
|
||||
|
||||
use crate::prelude::{ColorFormat, DisplayInfo, FrameBuffer};
|
||||
use crate::scheme::{DisplayScheme, Scheme};
|
||||
|
||||
pub struct MockDisplay {
|
||||
info: DisplayInfo,
|
||||
fb: Vec<u8>,
|
||||
}
|
||||
|
||||
impl MockDisplay {
|
||||
pub fn new(width: u32, height: u32, format: ColorFormat) -> Self {
|
||||
let fb_size = (width * height * format.bytes() as u32) as usize;
|
||||
let fb = vec![0; fb_size];
|
||||
let info = DisplayInfo {
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
fb_base_vaddr: fb.as_ptr() as usize,
|
||||
fb_size,
|
||||
};
|
||||
Self { info, fb }
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe, the caller must ensure the `ptr` points to the
|
||||
/// start of a valid frame buffer.
|
||||
pub unsafe fn from_raw_parts(
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: ColorFormat,
|
||||
ptr: *mut u8,
|
||||
) -> Self {
|
||||
let fb_size = (width * height * format.bytes() as u32) as usize;
|
||||
let fb = Vec::from_raw_parts(ptr, fb_size, fb_size);
|
||||
let info = DisplayInfo {
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
fb_base_vaddr: fb.as_ptr() as usize,
|
||||
fb_size,
|
||||
};
|
||||
Self { info, fb }
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheme for MockDisplay {
|
||||
fn name(&self) -> &str {
|
||||
"mock-display"
|
||||
}
|
||||
}
|
||||
|
||||
impl DisplayScheme for MockDisplay {
|
||||
#[inline]
|
||||
fn info(&self) -> DisplayInfo {
|
||||
self.info
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fb(&self) -> FrameBuffer {
|
||||
unsafe { FrameBuffer::from_raw_parts_mut(self.fb.as_ptr() as _, self.info.fb_size) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
pub mod sdl;
|
||||
|
|
@ -1,423 +0,0 @@
|
|||
use alloc::sync::Arc;
|
||||
|
||||
use sdl2::{event::Event, EventPump};
|
||||
use sdl2::{keyboard::Scancode, mouse::MouseButton};
|
||||
use sdl2::{pixels::PixelFormatEnum, render::Canvas, video::Window};
|
||||
|
||||
use crate::input::input_event_codes::{key::*, rel::*, syn::*};
|
||||
use crate::prelude::{ColorFormat, InputEvent, InputEventType};
|
||||
use crate::scheme::{DisplayScheme, InputScheme};
|
||||
|
||||
pub struct SdlWindow {
|
||||
canvas: Canvas<Window>,
|
||||
event_pump: EventPump,
|
||||
display: Arc<dyn DisplayScheme>,
|
||||
handler: EventHandler,
|
||||
is_quit: bool,
|
||||
}
|
||||
|
||||
impl SdlWindow {
|
||||
pub fn new(title: &str, display: Arc<dyn DisplayScheme>) -> Self {
|
||||
let sdl_context = sdl2::init().unwrap();
|
||||
let video_subsystem = sdl_context.video().unwrap();
|
||||
let window = video_subsystem
|
||||
.window(title, display.info().width, display.info().height)
|
||||
.position_centered()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let event_pump = sdl_context.event_pump().unwrap();
|
||||
let canvas = window.into_canvas().build().unwrap();
|
||||
let mut ret = Self {
|
||||
canvas,
|
||||
event_pump,
|
||||
display,
|
||||
handler: EventHandler::default(),
|
||||
is_quit: false,
|
||||
};
|
||||
ret.flush();
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn is_quit(&self) -> bool {
|
||||
self.is_quit
|
||||
}
|
||||
|
||||
pub fn register_mouse(&mut self, mouse: Arc<dyn InputScheme>) {
|
||||
self.handler.mouse = Some(mouse);
|
||||
}
|
||||
|
||||
pub fn register_keyboard(&mut self, keyboard: Arc<dyn InputScheme>) {
|
||||
self.handler.keyboard = Some(keyboard);
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) {
|
||||
let info = self.display.info();
|
||||
let texture_creator = self.canvas.texture_creator();
|
||||
let format: PixelFormatEnum = info.format.into();
|
||||
let mut texture = texture_creator
|
||||
.create_texture_streaming(format, info.width, info.height)
|
||||
.unwrap();
|
||||
|
||||
texture
|
||||
.update(None, &self.display.fb(), info.pitch() as usize)
|
||||
.unwrap();
|
||||
self.canvas.copy(&texture, None, None).unwrap();
|
||||
self.canvas.present();
|
||||
}
|
||||
|
||||
pub fn handle_events(&mut self) {
|
||||
for event in self.event_pump.poll_iter() {
|
||||
match event {
|
||||
Event::Quit { .. } => self.is_quit = true,
|
||||
Event::MouseMotion { xrel, yrel, .. } => self.handler.mouse_move(xrel, yrel),
|
||||
Event::MouseButtonDown { mouse_btn, .. } => {
|
||||
self.handler.mouse_button(mouse_btn, true)
|
||||
}
|
||||
Event::MouseButtonUp { mouse_btn, .. } => {
|
||||
self.handler.mouse_button(mouse_btn, false)
|
||||
}
|
||||
Event::KeyDown {
|
||||
scancode: Some(code),
|
||||
..
|
||||
} => {
|
||||
self.handler.key(code, true);
|
||||
if code == Scancode::Escape {
|
||||
self.is_quit = true;
|
||||
}
|
||||
}
|
||||
Event::KeyUp {
|
||||
scancode: Some(code),
|
||||
..
|
||||
} => self.handler.key(code, false),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct EventHandler {
|
||||
mouse: Option<Arc<dyn InputScheme>>,
|
||||
keyboard: Option<Arc<dyn InputScheme>>,
|
||||
}
|
||||
|
||||
impl EventHandler {
|
||||
fn mouse_move(&self, rel_x: i32, rel_y: i32) {
|
||||
if let Some(ref m) = self.mouse {
|
||||
m.trigger(InputEvent {
|
||||
event_type: InputEventType::RelAxis,
|
||||
code: REL_X,
|
||||
value: rel_x,
|
||||
});
|
||||
m.trigger(InputEvent {
|
||||
event_type: InputEventType::RelAxis,
|
||||
code: REL_Y,
|
||||
value: rel_y,
|
||||
});
|
||||
m.trigger(InputEvent {
|
||||
event_type: InputEventType::Syn,
|
||||
code: SYN_REPORT,
|
||||
value: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn mouse_button(&self, btn: MouseButton, down: bool) {
|
||||
if let Some(ref m) = self.mouse {
|
||||
let code = match btn {
|
||||
MouseButton::Left => BTN_LEFT,
|
||||
MouseButton::Right => BTN_RIGHT,
|
||||
MouseButton::Middle => BTN_MIDDLE,
|
||||
_ => return,
|
||||
};
|
||||
let value = if down { 1 } else { 0 };
|
||||
m.trigger(InputEvent {
|
||||
event_type: InputEventType::Key,
|
||||
code,
|
||||
value,
|
||||
});
|
||||
m.trigger(InputEvent {
|
||||
event_type: InputEventType::Syn,
|
||||
code: SYN_REPORT,
|
||||
value: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn key(&self, scancode: Scancode, down: bool) {
|
||||
if let Some(ref m) = self.keyboard {
|
||||
if let Some(code) = scancode_2_eventcode(scancode) {
|
||||
let value = if down { 1 } else { 0 };
|
||||
m.trigger(InputEvent {
|
||||
event_type: InputEventType::Key,
|
||||
code,
|
||||
value,
|
||||
});
|
||||
m.trigger(InputEvent {
|
||||
event_type: InputEventType::Syn,
|
||||
code: SYN_REPORT,
|
||||
value: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::convert::From<ColorFormat> for PixelFormatEnum {
|
||||
fn from(format: ColorFormat) -> Self {
|
||||
match format {
|
||||
ColorFormat::RGB332 => Self::RGB332,
|
||||
ColorFormat::RGB565 => Self::RGB565,
|
||||
ColorFormat::RGB888 => Self::BGR24, // notice: BGR24 means R at the highest address, B at the lowest address.
|
||||
ColorFormat::ARGB8888 => Self::ARGB8888,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn scancode_2_eventcode(code: Scancode) -> Option<u16> {
|
||||
use Scancode::*;
|
||||
Some(match code {
|
||||
A => KEY_A,
|
||||
B => KEY_B,
|
||||
C => KEY_C,
|
||||
D => KEY_D,
|
||||
E => KEY_E,
|
||||
F => KEY_F,
|
||||
G => KEY_G,
|
||||
H => KEY_H,
|
||||
I => KEY_I,
|
||||
J => KEY_J,
|
||||
K => KEY_K,
|
||||
L => KEY_L,
|
||||
M => KEY_M,
|
||||
N => KEY_N,
|
||||
O => KEY_O,
|
||||
P => KEY_P,
|
||||
Q => KEY_Q,
|
||||
R => KEY_R,
|
||||
S => KEY_S,
|
||||
T => KEY_T,
|
||||
U => KEY_U,
|
||||
V => KEY_V,
|
||||
W => KEY_W,
|
||||
X => KEY_X,
|
||||
Y => KEY_Y,
|
||||
Z => KEY_Z,
|
||||
Num1 => KEY_1,
|
||||
Num2 => KEY_2,
|
||||
Num3 => KEY_3,
|
||||
Num4 => KEY_4,
|
||||
Num5 => KEY_5,
|
||||
Num6 => KEY_6,
|
||||
Num7 => KEY_7,
|
||||
Num8 => KEY_8,
|
||||
Num9 => KEY_9,
|
||||
Num0 => KEY_0,
|
||||
Return => KEY_ENTER,
|
||||
Escape => KEY_ESC,
|
||||
Backspace => KEY_BACKSPACE,
|
||||
Tab => KEY_TAB,
|
||||
Space => KEY_SPACE,
|
||||
Minus => KEY_MINUS,
|
||||
Equals => KEY_EQUAL,
|
||||
LeftBracket => KEY_LEFTBRACE,
|
||||
RightBracket => KEY_RIGHTBRACE,
|
||||
Backslash => KEY_BACKSLASH,
|
||||
NonUsHash => return None,
|
||||
Semicolon => KEY_SEMICOLON,
|
||||
Apostrophe => KEY_APOSTROPHE,
|
||||
Grave => KEY_GRAVE,
|
||||
Comma => KEY_COMMA,
|
||||
Period => KEY_DOT,
|
||||
Slash => KEY_SLASH,
|
||||
CapsLock => KEY_CAPSLOCK,
|
||||
F1 => KEY_F1,
|
||||
F2 => KEY_F2,
|
||||
F3 => KEY_F3,
|
||||
F4 => KEY_F4,
|
||||
F5 => KEY_F5,
|
||||
F6 => KEY_F6,
|
||||
F7 => KEY_F7,
|
||||
F8 => KEY_F8,
|
||||
F9 => KEY_F9,
|
||||
F10 => KEY_F10,
|
||||
F11 => KEY_F11,
|
||||
F12 => KEY_F12,
|
||||
PrintScreen => return None,
|
||||
ScrollLock => KEY_SCROLLLOCK,
|
||||
Pause => KEY_PAUSE,
|
||||
Insert => KEY_INSERT,
|
||||
Home => KEY_HOME,
|
||||
PageUp => KEY_PAGEUP,
|
||||
Delete => KEY_DELETE,
|
||||
End => KEY_END,
|
||||
PageDown => KEY_PAGEDOWN,
|
||||
Right => KEY_RIGHT,
|
||||
Left => KEY_LEFT,
|
||||
Down => KEY_DOWN,
|
||||
Up => KEY_UP,
|
||||
NumLockClear => KEY_NUMLOCK,
|
||||
KpDivide => KEY_KPSLASH,
|
||||
KpMultiply => KEY_KPASTERISK,
|
||||
KpMinus => KEY_KPMINUS,
|
||||
KpPlus => KEY_KPPLUS,
|
||||
KpEnter => KEY_KPENTER,
|
||||
Kp1 => KEY_KP1,
|
||||
Kp2 => KEY_KP2,
|
||||
Kp3 => KEY_KP3,
|
||||
Kp4 => KEY_KP4,
|
||||
Kp5 => KEY_KP5,
|
||||
Kp6 => KEY_KP6,
|
||||
Kp7 => KEY_KP7,
|
||||
Kp8 => KEY_KP8,
|
||||
Kp9 => KEY_KP9,
|
||||
Kp0 => KEY_KP0,
|
||||
KpPeriod => KEY_KPDOT,
|
||||
NonUsBackslash => KEY_102ND,
|
||||
Application => return None,
|
||||
Power => KEY_POWER,
|
||||
KpEquals => KEY_KPEQUAL,
|
||||
F13 => KEY_F13,
|
||||
F14 => KEY_F14,
|
||||
F15 => KEY_F15,
|
||||
F16 => KEY_F16,
|
||||
F17 => KEY_F17,
|
||||
F18 => KEY_F18,
|
||||
F19 => KEY_F19,
|
||||
F20 => KEY_F20,
|
||||
F21 => KEY_F21,
|
||||
F22 => KEY_F22,
|
||||
F23 => KEY_F23,
|
||||
F24 => KEY_F24,
|
||||
Execute => return None,
|
||||
Help => KEY_HELP,
|
||||
Menu => KEY_MENU,
|
||||
Select => return None,
|
||||
Stop => KEY_STOP,
|
||||
Again => KEY_AGAIN,
|
||||
Undo => KEY_UNDO,
|
||||
Cut => KEY_CUT,
|
||||
Copy => KEY_COPY,
|
||||
Paste => KEY_PASTE,
|
||||
Find => KEY_FIND,
|
||||
Mute => KEY_MUTE,
|
||||
VolumeUp => KEY_VOLUMEUP,
|
||||
VolumeDown => KEY_VOLUMEDOWN,
|
||||
KpComma => KEY_KPCOMMA,
|
||||
KpEqualsAS400 => return None,
|
||||
International1 => KEY_RO,
|
||||
International2 => KEY_KATAKANAHIRAGANA,
|
||||
International3 => KEY_YEN,
|
||||
International4 => KEY_HENKAN,
|
||||
International5 => KEY_MUHENKAN,
|
||||
International6 => return None,
|
||||
International7 => return None,
|
||||
International8 => return None,
|
||||
International9 => return None,
|
||||
Lang1 => KEY_HANGEUL,
|
||||
Lang2 => KEY_HANJA,
|
||||
Lang3 => KEY_KATAKANA,
|
||||
Lang4 => KEY_HIRAGANA,
|
||||
Lang5 => return None,
|
||||
Lang6 => return None,
|
||||
Lang7 => return None,
|
||||
Lang8 => return None,
|
||||
Lang9 => return None,
|
||||
AltErase => KEY_ALTERASE,
|
||||
SysReq => KEY_SYSRQ,
|
||||
Cancel => KEY_CANCEL,
|
||||
Clear => return None,
|
||||
Prior => return None,
|
||||
Return2 => return None,
|
||||
Separator => return None,
|
||||
Out => return None,
|
||||
Oper => return None,
|
||||
ClearAgain => return None,
|
||||
CrSel => return None,
|
||||
ExSel => return None,
|
||||
Kp00 => return None,
|
||||
Kp000 => return None,
|
||||
ThousandsSeparator => return None,
|
||||
DecimalSeparator => return None,
|
||||
CurrencyUnit => return None,
|
||||
CurrencySubUnit => return None,
|
||||
KpLeftParen => KEY_KPLEFTPAREN,
|
||||
KpRightParen => KEY_KPRIGHTPAREN,
|
||||
KpLeftBrace => return None,
|
||||
KpRightBrace => return None,
|
||||
KpTab => return None,
|
||||
KpBackspace => return None,
|
||||
KpA => return None,
|
||||
KpB => return None,
|
||||
KpC => return None,
|
||||
KpD => return None,
|
||||
KpE => return None,
|
||||
KpF => return None,
|
||||
KpXor => return None,
|
||||
KpPower => return None,
|
||||
KpPercent => return None,
|
||||
KpLess => return None,
|
||||
KpGreater => return None,
|
||||
KpAmpersand => return None,
|
||||
KpDblAmpersand => return None,
|
||||
KpVerticalBar => return None,
|
||||
KpDblVerticalBar => return None,
|
||||
KpColon => return None,
|
||||
KpHash => return None,
|
||||
KpSpace => return None,
|
||||
KpAt => return None,
|
||||
KpExclam => return None,
|
||||
KpMemStore => return None,
|
||||
KpMemRecall => return None,
|
||||
KpMemClear => return None,
|
||||
KpMemAdd => return None,
|
||||
KpMemSubtract => return None,
|
||||
KpMemMultiply => return None,
|
||||
KpMemDivide => return None,
|
||||
KpPlusMinus => KEY_KPPLUSMINUS,
|
||||
KpClear => return None,
|
||||
KpClearEntry => return None,
|
||||
KpBinary => return None,
|
||||
KpOctal => return None,
|
||||
KpDecimal => return None,
|
||||
KpHexadecimal => return None,
|
||||
LCtrl => KEY_LEFTCTRL,
|
||||
LShift => KEY_LEFTSHIFT,
|
||||
LAlt => KEY_LEFTALT,
|
||||
LGui => KEY_LEFTMETA,
|
||||
RCtrl => KEY_RIGHTCTRL,
|
||||
RShift => KEY_RIGHTSHIFT,
|
||||
RAlt => KEY_RIGHTALT,
|
||||
RGui => KEY_RIGHTMETA,
|
||||
Mode => return None,
|
||||
AudioNext => KEY_NEXTSONG,
|
||||
AudioPrev => KEY_PREVIOUSSONG,
|
||||
AudioStop => return None,
|
||||
AudioPlay => KEY_PLAYPAUSE,
|
||||
AudioMute => return None,
|
||||
MediaSelect => return None,
|
||||
Www => return None,
|
||||
Mail => KEY_MAIL,
|
||||
Calculator => KEY_CALC,
|
||||
Computer => KEY_COMPUTER,
|
||||
AcSearch => KEY_SEARCH,
|
||||
AcHome => KEY_HOMEPAGE,
|
||||
AcBack => KEY_BACK,
|
||||
AcForward => KEY_FORWARD,
|
||||
AcStop => return None,
|
||||
AcRefresh => KEY_REFRESH,
|
||||
AcBookmarks => KEY_BOOKMARKS,
|
||||
BrightnessDown => KEY_BRIGHTNESSDOWN,
|
||||
BrightnessUp => KEY_BRIGHTNESSUP,
|
||||
DisplaySwitch => KEY_SWITCHVIDEOMODE,
|
||||
KbdIllumToggle => KEY_KBDILLUMTOGGLE,
|
||||
KbdIllumDown => KEY_KBDILLUMDOWN,
|
||||
KbdIllumUp => KEY_KBDILLUMUP,
|
||||
Eject => KEY_EJECTCD,
|
||||
Sleep => KEY_SLEEP,
|
||||
App1 => return None,
|
||||
App2 => return None,
|
||||
Num => return None,
|
||||
})
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
use crate::input::input_event_codes::{ev::*, key::*, rel::*};
|
||||
use crate::prelude::{CapabilityType, InputCapability, InputEvent};
|
||||
use crate::scheme::{impl_event_scheme, InputScheme, Scheme};
|
||||
use crate::utils::EventListener;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MockMouse {
|
||||
listener: EventListener<InputEvent>,
|
||||
}
|
||||
|
||||
impl_event_scheme!(MockMouse, InputEvent);
|
||||
|
||||
impl Scheme for MockMouse {
|
||||
fn name(&self) -> &str {
|
||||
"mock-mouse-input"
|
||||
}
|
||||
}
|
||||
|
||||
impl InputScheme for MockMouse {
|
||||
fn capability(&self, cap_type: CapabilityType) -> InputCapability {
|
||||
let mut cap = InputCapability::empty();
|
||||
match cap_type {
|
||||
CapabilityType::Event => cap.set_all(&[EV_KEY, EV_REL]),
|
||||
CapabilityType::Key => cap.set_all(&[BTN_LEFT, BTN_RIGHT, BTN_MIDDLE]),
|
||||
CapabilityType::RelAxis => cap.set_all(&[REL_X, REL_Y, REL_HWHEEL]),
|
||||
_ => {}
|
||||
}
|
||||
cap
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MockKeyboard {
|
||||
listener: EventListener<InputEvent>,
|
||||
}
|
||||
|
||||
impl_event_scheme!(MockKeyboard, InputEvent);
|
||||
|
||||
impl Scheme for MockKeyboard {
|
||||
fn name(&self) -> &str {
|
||||
"mock-keyboard-input"
|
||||
}
|
||||
}
|
||||
|
||||
impl InputScheme for MockKeyboard {
|
||||
fn capability(&self, cap_type: CapabilityType) -> InputCapability {
|
||||
let mut cap = InputCapability::empty();
|
||||
match cap_type {
|
||||
CapabilityType::Event => cap.set(EV_KEY),
|
||||
CapabilityType::Key => {
|
||||
// TODO
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
cap
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
//! Mock devices, including display, input, uart and graphic.
|
||||
|
||||
pub mod display;
|
||||
pub mod input;
|
||||
pub mod uart;
|
||||
|
||||
#[cfg(any(feature = "graphic", doc))]
|
||||
#[doc(cfg(feature = "graphic"))]
|
||||
pub mod graphic;
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use async_std::{io, io::prelude::*, task};
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
|
||||
use crate::utils::EventListener;
|
||||
use crate::DeviceResult;
|
||||
|
||||
const UART_BUF_LEN: usize = 256;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref UART_BUF: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::with_capacity(UART_BUF_LEN));
|
||||
}
|
||||
|
||||
pub struct MockUart {
|
||||
listener: EventListener,
|
||||
}
|
||||
|
||||
impl_event_scheme!(MockUart);
|
||||
|
||||
impl MockUart {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
listener: EventListener::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_irq_service(irq_handler: impl Fn() + Send + Sync + 'static) {
|
||||
task::spawn(async move {
|
||||
loop {
|
||||
let mut buf = [0; UART_BUF_LEN];
|
||||
let remains = UART_BUF_LEN - UART_BUF.lock().len();
|
||||
if remains > 0 {
|
||||
if let Ok(n) = io::stdin().read(&mut buf[..remains]).await {
|
||||
{
|
||||
let mut uart_buf = UART_BUF.lock();
|
||||
for c in &buf[..n] {
|
||||
uart_buf.push_back(*c);
|
||||
}
|
||||
}
|
||||
irq_handler();
|
||||
}
|
||||
}
|
||||
task::yield_now().await;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MockUart {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheme for MockUart {
|
||||
fn name(&self) -> &str {
|
||||
"mock-uart"
|
||||
}
|
||||
|
||||
fn handle_irq(&self, _irq_num: usize) {
|
||||
self.listener.trigger(());
|
||||
}
|
||||
}
|
||||
|
||||
impl UartScheme for MockUart {
|
||||
fn try_recv(&self) -> DeviceResult<Option<u8>> {
|
||||
if let Some(c) = UART_BUF.lock().pop_front() {
|
||||
Ok(Some(c))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn send(&self, ch: u8) -> DeviceResult {
|
||||
eprint!("{}", ch as char);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_str(&self, s: &str) -> DeviceResult {
|
||||
eprint!("{}", s);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn test_mock_uart() {
|
||||
let uart = Arc::new(MockUart::new());
|
||||
let u = uart.clone();
|
||||
MockUart::start_irq_service(move || u.handle_irq(0));
|
||||
|
||||
uart.write_str("Hello, World!\n").unwrap();
|
||||
uart.write_str(format!("{} + {} = {}\n", 1, 2, 1 + 2).as_str())
|
||||
.unwrap();
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
if let Some(ch) = uart.try_recv().unwrap() {
|
||||
uart.write_str(format!("received data: {:?}({:#x})\n", ch as char, ch).as_str())
|
||||
.unwrap();
|
||||
} else {
|
||||
uart.write_str("no data to receive\n").unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
//! Intel PRO/1000 Network Adapter i.e. e1000 network driver
|
||||
//! Datasheet: https://www.intel.ca/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
|
||||
|
||||
use alloc::collections::BTreeMap;
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use smoltcp::iface::*;
|
||||
use smoltcp::phy::{self, DeviceCapabilities};
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::*;
|
||||
use smoltcp::Result;
|
||||
|
||||
use super::ProviderImpl;
|
||||
use super::PAGE_SIZE;
|
||||
use crate::net::get_sockets;
|
||||
use crate::scheme::{NetScheme, Scheme};
|
||||
use crate::{DeviceError, DeviceResult};
|
||||
use isomorphic_drivers::net::ethernet::intel::e1000::E1000;
|
||||
use isomorphic_drivers::net::ethernet::structs::EthernetAddress as DriverEthernetAddress;
|
||||
use lock::Mutex;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct E1000Driver(Arc<Mutex<E1000<ProviderImpl>>>);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct E1000Interface {
|
||||
iface: Arc<Mutex<Interface<'static, E1000Driver>>>,
|
||||
driver: E1000Driver,
|
||||
name: String,
|
||||
irq: usize,
|
||||
}
|
||||
|
||||
impl Scheme for E1000Interface {
|
||||
fn name(&self) -> &str {
|
||||
"e1000"
|
||||
}
|
||||
|
||||
fn handle_irq(&self, irq: usize) {
|
||||
if irq != self.irq {
|
||||
// not ours, skip it
|
||||
return;
|
||||
}
|
||||
|
||||
let data = self.driver.0.lock().handle_interrupt();
|
||||
|
||||
if data {
|
||||
//let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
|
||||
// Fix me
|
||||
let timestamp = Instant::from_millis(0);
|
||||
let sockets = get_sockets();
|
||||
let mut sockets = sockets.lock();
|
||||
match self.iface.lock().poll(&mut sockets, timestamp) {
|
||||
Ok(p) => {
|
||||
//SOCKET_ACTIVITY.notify_all();
|
||||
info!("e1000 try_handle_interrupt poll: {:?}", p);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("poll got err {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetScheme for E1000Interface {
|
||||
fn get_mac(&self) -> EthernetAddress {
|
||||
self.iface.lock().ethernet_addr()
|
||||
}
|
||||
|
||||
fn get_ifname(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
// get ip addresses
|
||||
fn get_ip_address(&self) -> Vec<IpCidr> {
|
||||
Vec::from(self.iface.lock().ip_addrs())
|
||||
}
|
||||
|
||||
fn poll(&self) -> DeviceResult {
|
||||
//let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
|
||||
let timestamp = Instant::from_millis(0);
|
||||
let sockets = get_sockets();
|
||||
let mut sockets = sockets.lock();
|
||||
match self.iface.lock().poll(&mut sockets, timestamp) {
|
||||
Ok(p) => {
|
||||
//SOCKET_ACTIVITY.notify_all();
|
||||
info!("e1000 NetScheme poll: {:?}", p);
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("poll got err {}", err);
|
||||
Err(DeviceError::IoError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn recv(&self, buf: &mut [u8]) -> DeviceResult<usize> {
|
||||
if let Some(vec_recv) = self.driver.0.lock().receive() {
|
||||
buf.copy_from_slice(&vec_recv);
|
||||
Ok(vec_recv.len())
|
||||
} else {
|
||||
Err(DeviceError::NotReady)
|
||||
}
|
||||
}
|
||||
|
||||
fn send(&self, data: &[u8]) -> DeviceResult<usize> {
|
||||
if self.driver.0.lock().can_send() {
|
||||
let mut driver = self.driver.0.lock();
|
||||
driver.send(data);
|
||||
Ok(data.len())
|
||||
} else {
|
||||
Err(DeviceError::NotReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct E1000RxToken(Vec<u8>);
|
||||
pub struct E1000TxToken(E1000Driver);
|
||||
|
||||
impl phy::Device<'_> for E1000Driver {
|
||||
type RxToken = E1000RxToken;
|
||||
type TxToken = E1000TxToken;
|
||||
|
||||
fn receive(&mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
||||
self.0
|
||||
.lock()
|
||||
.receive()
|
||||
.map(|vec| (E1000RxToken(vec), E1000TxToken(self.clone())))
|
||||
}
|
||||
|
||||
fn transmit(&mut self) -> Option<Self::TxToken> {
|
||||
if self.0.lock().can_send() {
|
||||
Some(E1000TxToken(self.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn capabilities(&self) -> DeviceCapabilities {
|
||||
let mut caps = DeviceCapabilities::default();
|
||||
caps.max_transmission_unit = 1536;
|
||||
caps.max_burst_size = Some(64);
|
||||
caps
|
||||
}
|
||||
}
|
||||
|
||||
impl phy::RxToken for E1000RxToken {
|
||||
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> Result<R>,
|
||||
{
|
||||
f(&mut self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl phy::TxToken for E1000TxToken {
|
||||
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> Result<R>,
|
||||
{
|
||||
let mut buffer = [0u8; PAGE_SIZE];
|
||||
let result = f(&mut buffer[..len]);
|
||||
|
||||
let mut driver = (self.0).0.lock();
|
||||
driver.send(&buffer);
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
// JudgeDuck-OS/kern/e1000.c
|
||||
pub fn init(
|
||||
name: String,
|
||||
irq: usize,
|
||||
header: usize,
|
||||
size: usize,
|
||||
index: usize,
|
||||
) -> DeviceResult<E1000Interface> {
|
||||
info!("Probing e1000 {}", name);
|
||||
|
||||
// randomly generated
|
||||
let mac: [u8; 6] = [0x54, 0x51, 0x9F, 0x71, 0xC0, index as u8];
|
||||
|
||||
let e1000 = E1000::new(header, size, DriverEthernetAddress::from_bytes(&mac));
|
||||
|
||||
let net_driver = E1000Driver(Arc::new(Mutex::new(e1000)));
|
||||
|
||||
let ethernet_addr = EthernetAddress::from_bytes(&mac);
|
||||
let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 2, (15 + index) as u8), 24)];
|
||||
let default_v4_gw = Ipv4Address::new(10, 0, 2, 2); //Qemu user network gateway: 10.0.2.2
|
||||
static mut ROUTES_STORAGE: [Option<(IpCidr, Route)>; 1] = [None; 1];
|
||||
let mut routes = unsafe { Routes::new(&mut ROUTES_STORAGE[..]) };
|
||||
routes.add_default_ipv4_route(default_v4_gw).unwrap();
|
||||
|
||||
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||
let iface = InterfaceBuilder::new(net_driver.clone())
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.ip_addrs(ip_addrs)
|
||||
.routes(routes)
|
||||
.finalize();
|
||||
|
||||
info!(
|
||||
"e1000 interface {} up with addr 10.0.2.{}/24",
|
||||
name,
|
||||
15 + index
|
||||
);
|
||||
let e1000_iface = E1000Interface {
|
||||
iface: Arc::new(Mutex::new(iface)),
|
||||
driver: net_driver,
|
||||
name,
|
||||
irq,
|
||||
};
|
||||
|
||||
Ok(e1000_iface)
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
// smoltcp
|
||||
use smoltcp::{iface::Interface, phy::Loopback, time::Instant};
|
||||
|
||||
use crate::net::get_sockets;
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use alloc::string::String;
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::scheme::{NetScheme, Scheme};
|
||||
use crate::{DeviceError, DeviceResult};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use smoltcp::wire::EthernetAddress;
|
||||
use smoltcp::wire::IpCidr;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LoopbackInterface {
|
||||
pub iface: Arc<Mutex<Interface<'static, Loopback>>>,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl Scheme for LoopbackInterface {
|
||||
fn name(&self) -> &str {
|
||||
"loopback"
|
||||
}
|
||||
|
||||
fn handle_irq(&self, _cause: usize) {}
|
||||
}
|
||||
|
||||
impl NetScheme for LoopbackInterface {
|
||||
fn recv(&self, _buf: &mut [u8]) -> DeviceResult<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn send(&self, _buf: &[u8]) -> DeviceResult<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn poll(&self) -> DeviceResult {
|
||||
let timestamp = Instant::from_millis(0);
|
||||
let sockets = get_sockets();
|
||||
let mut sockets = sockets.lock();
|
||||
match self.iface.lock().poll(&mut sockets, timestamp) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
debug!("poll got err {}", err);
|
||||
Err(DeviceError::IoError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mac(&self) -> EthernetAddress {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_ifname(&self) -> String {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_ip_address(&self) -> Vec<IpCidr> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
//! LAN driver, only for Realtek currently.
|
||||
|
||||
pub mod e1000;
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "riscv64")] {
|
||||
mod realtek;
|
||||
mod rtlx;
|
||||
|
||||
pub use rtlx::*;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// 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 use isomorphic_drivers::provider::Provider;
|
||||
|
||||
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) }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn drivers_dma_alloc(pages: usize) -> PhysAddr;
|
||||
fn drivers_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32;
|
||||
fn drivers_phys_to_virt(paddr: PhysAddr) -> VirtAddr;
|
||||
fn drivers_virt_to_phys(vaddr: VirtAddr) -> PhysAddr;
|
||||
}
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
|
||||
type VirtAddr = usize;
|
||||
type PhysAddr = usize;
|
||||
|
||||
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()
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
// From Linux
|
||||
|
||||
/* Generic MII registers. */
|
||||
pub const MII_BMCR: u32 = 0x00;
|
||||
pub const MII_BMSR: u32 = 0x01;
|
||||
pub const MII_PHYSID1: u32 = 0x02;
|
||||
pub const MII_PHYSID2: u32 = 0x03;
|
||||
pub const MII_ADVERTISE: u32 = 0x04;
|
||||
pub const MII_LPA: u32 = 0x05;
|
||||
pub const MII_EXPANSION: u32 = 0x06;
|
||||
pub const MII_CTRL1000: u32 = 0x09;
|
||||
pub const MII_STAT1000: u32 = 0x0a;
|
||||
pub const MII_MMD_CTRL: u32 = 0x0d;
|
||||
pub const MII_MMD_DATA: u32 = 0x0e;
|
||||
pub const MII_ESTATUS: u32 = 0x0f;
|
||||
pub const MII_DCOUNTER: u32 = 0x12;
|
||||
pub const MII_FCSCOUNTER: u32 = 0x13;
|
||||
pub const MII_NWAYTEST: u32 = 0x14;
|
||||
pub const MII_RERRCOUNTER: u32 = 0x15;
|
||||
pub const MII_SREVISION: u32 = 0x16;
|
||||
pub const MII_RESV1: u32 = 0x17;
|
||||
pub const MII_LBRERROR: u32 = 0x18;
|
||||
pub const MII_PHYADDR: u32 = 0x19;
|
||||
pub const MII_RESV2: u32 = 0x1a;
|
||||
pub const MII_TPISTATUS: u32 = 0x1b;
|
||||
pub const MII_NCONFIG: u32 = 0x1c;
|
||||
|
||||
/* Basic mode control register. */
|
||||
pub const BMCR_RESV: u32 = 0x003f;
|
||||
pub const BMCR_SPEED1000: u32 = 0x0040;
|
||||
pub const BMCR_CTST: u32 = 0x0080;
|
||||
pub const BMCR_FULLDPLX: u32 = 0x0100;
|
||||
pub const BMCR_ANRESTART: u32 = 0x0200;
|
||||
pub const BMCR_ISOLATE: u32 = 0x0400;
|
||||
pub const BMCR_PDOWN: u32 = 0x0800;
|
||||
pub const BMCR_ANENABLE: u32 = 0x1000;
|
||||
pub const BMCR_SPEED100: u32 = 0x2000;
|
||||
pub const BMCR_LOOPBACK: u32 = 0x4000;
|
||||
pub const BMCR_RESET: u32 = 0x8000;
|
||||
pub const BMCR_SPEED10: u32 = 0x0000;
|
||||
|
||||
/* Basic mode status register. */
|
||||
pub const BMSR_ERCAP: u32 = 0x0001;
|
||||
pub const BMSR_JCD: u32 = 0x0002;
|
||||
pub const BMSR_LSTATUS: u32 = 0x0004;
|
||||
pub const BMSR_ANEGCAPABLE: u32 = 0x0008;
|
||||
pub const BMSR_RFAULT: u32 = 0x0010;
|
||||
pub const BMSR_ANEGCOMPLETE: u32 = 0x0020;
|
||||
pub const BMSR_RESV: u32 = 0x00c0;
|
||||
pub const BMSR_ESTATEN: u32 = 0x0100;
|
||||
pub const BMSR_100HALF2: u32 = 0x0200;
|
||||
pub const BMSR_100FULL2: u32 = 0x0400;
|
||||
pub const BMSR_10HALF: u32 = 0x0800;
|
||||
pub const BMSR_10FULL: u32 = 0x1000;
|
||||
pub const BMSR_100HALF: u32 = 0x2000;
|
||||
pub const BMSR_100FULL: u32 = 0x4000;
|
||||
pub const BMSR_100BASE4: u32 = 0x8000;
|
||||
|
||||
/* Advertisement control register. */
|
||||
pub const ADVERTISE_SLCT: u32 = 0x001f;
|
||||
pub const ADVERTISE_CSMA: u32 = 0x0001;
|
||||
pub const ADVERTISE_10HALF: u32 = 0x0020;
|
||||
pub const ADVERTISE_1000XFULL: u32 = 0x0020;
|
||||
pub const ADVERTISE_10FULL: u32 = 0x0040;
|
||||
pub const ADVERTISE_1000XHALF: u32 = 0x0040;
|
||||
pub const ADVERTISE_100HALF: u32 = 0x0080;
|
||||
pub const ADVERTISE_1000XPAUSE: u32 = 0x0080;
|
||||
pub const ADVERTISE_100FULL: u32 = 0x0100;
|
||||
pub const ADVERTISE_1000XPSE_ASYM: u32 = 0x0100;
|
||||
pub const ADVERTISE_100BASE4: u32 = 0x0200;
|
||||
pub const ADVERTISE_PAUSE_CAP: u32 = 0x0400;
|
||||
pub const ADVERTISE_PAUSE_ASYM: u32 = 0x0800;
|
||||
pub const ADVERTISE_RESV: u32 = 0x1000;
|
||||
pub const ADVERTISE_RFAULT: u32 = 0x2000;
|
||||
pub const ADVERTISE_LPACK: u32 = 0x4000;
|
||||
pub const ADVERTISE_NPAGE: u32 = 0x8000;
|
||||
|
||||
pub const ADVERTISE_FULL: u32 = ADVERTISE_100FULL | ADVERTISE_10FULL | ADVERTISE_CSMA;
|
||||
pub const ADVERTISE_ALL: u32 =
|
||||
ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL;
|
||||
|
||||
/* Link partner ability register. */
|
||||
pub const LPA_SLCT: u32 = 0x001f;
|
||||
pub const LPA_10HALF: u32 = 0x0020;
|
||||
pub const LPA_1000XFULL: u32 = 0x0020;
|
||||
pub const LPA_10FULL: u32 = 0x0040;
|
||||
pub const LPA_1000XHALF: u32 = 0x0040;
|
||||
pub const LPA_100HALF: u32 = 0x0080;
|
||||
pub const LPA_1000XPAUSE: u32 = 0x0080;
|
||||
pub const LPA_100FULL: u32 = 0x0100;
|
||||
pub const LPA_1000XPAUSE_ASYM: u32 = 0x0100;
|
||||
pub const LPA_100BASE4: u32 = 0x0200;
|
||||
pub const LPA_PAUSE_CAP: u32 = 0x0400;
|
||||
pub const LPA_PAUSE_ASYM: u32 = 0x0800;
|
||||
pub const LPA_RESV: u32 = 0x1000;
|
||||
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);
|
||||
|
||||
/* 1000BASE-T Control register */
|
||||
pub const ADVERTISE_1000FULL: u32 = 0x0200;
|
||||
pub const ADVERTISE_1000HALF: u32 = 0x0100;
|
||||
pub const CTL1000_AS_MASTER: u32 = 0x0800;
|
||||
pub const CTL1000_ENABLE_MASTER: u32 = 0x1000;
|
||||
|
||||
/* 1000BASE-T Status register */
|
||||
pub const LPA_1000MSFAIL: u32 = 0x8000;
|
||||
pub const LPA_1000LOCALRXOK: u32 = 0x2000;
|
||||
pub const LPA_1000REMRXOK: u32 = 0x1000;
|
||||
pub const LPA_1000FULL: u32 = 0x0800;
|
||||
pub const LPA_1000HALF: u32 = 0x0400;
|
||||
|
||||
/* Flow control flags */
|
||||
pub const FLOW_CTRL_TX: u32 = 0x01;
|
||||
pub const FLOW_CTRL_RX: u32 = 0x02;
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#![allow(unused)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use super::Provider;
|
||||
use super::{phys_to_virt, virt_to_phys};
|
||||
|
||||
#[macro_use]
|
||||
mod log {
|
||||
macro_rules! trace {
|
||||
($($arg:expr),*) => { $( let _ = $arg; )* };
|
||||
}
|
||||
macro_rules! debug {
|
||||
($($arg:expr),*) => { $( let _ = $arg; )* };
|
||||
}
|
||||
macro_rules! info {
|
||||
($($arg:expr),*) => { $( let _ = $arg; )*};
|
||||
}
|
||||
macro_rules! warn {
|
||||
($($arg:expr),*) => { $( let _ = $arg; )*};
|
||||
}
|
||||
macro_rules! error {
|
||||
($($arg:expr),*) => { $( let _ = $arg; )* };
|
||||
}
|
||||
}
|
||||
|
||||
pub mod mii;
|
||||
pub mod rtl8211f;
|
||||
mod utils;
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,91 +0,0 @@
|
|||
// c906
|
||||
use core::arch::asm;
|
||||
|
||||
const FREQUENCY: u64 = 24_000_000; // C906: 24_000_000, Qemu: 10_000_000
|
||||
const MMIO_MTIMECMP0: *mut u64 = 0x0200_4000usize as *mut u64;
|
||||
const MMIO_MTIME: *const u64 = 0x0200_BFF8 as *const u64;
|
||||
|
||||
const L1_CACHE_BYTES: u64 = 64;
|
||||
const CACHE_LINE_SIZE: u64 = 64;
|
||||
|
||||
pub fn flush_cache(addr: u64, size: u64) {
|
||||
flush_dcache_range(addr, addr + size);
|
||||
}
|
||||
|
||||
pub fn invalidate_dcache(addr: u64, size: u64) {
|
||||
invalidate_dcache_range(addr, addr + size);
|
||||
}
|
||||
|
||||
// 注意start输入物理地址
|
||||
pub fn flush_dcache_range(start: u64, end: u64) {
|
||||
// CACHE_LINE 64对齐
|
||||
let end = (end + (CACHE_LINE_SIZE - 1)) & !(CACHE_LINE_SIZE - 1);
|
||||
|
||||
// 地址对齐到L1 Cache的节
|
||||
let mut i: u64 = start & !(L1_CACHE_BYTES - 1);
|
||||
while i < end {
|
||||
unsafe {
|
||||
// 老风格的llvm asm
|
||||
// DCACHE 指定物理地址清脏表项
|
||||
// llvm_asm!("dcache.cpa $0"::"r"(i));
|
||||
|
||||
// 新asm
|
||||
asm!(".long 0x0295000b", in("a0") i); // dcache.cpa a0, 因编译器无法识别该指令
|
||||
}
|
||||
|
||||
i += L1_CACHE_BYTES;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
//llvm_asm!("sync.is");
|
||||
|
||||
asm!(".long 0x01b0000b"); // sync.is
|
||||
}
|
||||
}
|
||||
|
||||
// start 物理地址
|
||||
pub fn invalidate_dcache_range(start: u64, end: u64) {
|
||||
let end = (end + (CACHE_LINE_SIZE - 1)) & !(CACHE_LINE_SIZE - 1);
|
||||
let mut i: u64 = start & !(L1_CACHE_BYTES - 1);
|
||||
while i < end {
|
||||
unsafe {
|
||||
//llvm_asm!("dcache.ipa $0"::"r"(i)); // DCACHE 指定物理地址无效表项
|
||||
asm!(".long 0x02a5000b", in("a0") i); // dcache.ipa a0
|
||||
}
|
||||
|
||||
i += L1_CACHE_BYTES;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
//llvm_asm!("sync.is");
|
||||
asm!(".long 0x01b0000b"); // sync.is
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fence_w() {
|
||||
unsafe {
|
||||
//llvm_asm!("fence ow, ow" ::: "memory");
|
||||
asm!("fence ow, ow");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cycle() -> u64 {
|
||||
unsafe { MMIO_MTIME.read_volatile() }
|
||||
}
|
||||
|
||||
// Timer, Freq = 24000000Hz
|
||||
// TIMER_CLOCK = (24 * 1000 * 1000)
|
||||
// 微秒(us)
|
||||
pub fn usdelay(us: u64) {
|
||||
let mut t1: u64 = get_cycle();
|
||||
let t2 = t1 + us * 24;
|
||||
|
||||
while t2 >= t1 {
|
||||
t1 = get_cycle();
|
||||
}
|
||||
}
|
||||
|
||||
// 毫秒(ms)
|
||||
pub fn msdelay(ms: u64) {
|
||||
usdelay(ms * 1000);
|
||||
}
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
use alloc::collections::BTreeMap;
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
// use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use lock::Mutex;
|
||||
|
||||
use smoltcp::iface::*;
|
||||
use smoltcp::phy::{self, Device, DeviceCapabilities, Medium};
|
||||
// use smoltcp::socket::SocketSet;
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::*;
|
||||
use smoltcp::Result;
|
||||
|
||||
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};
|
||||
use crate::{DeviceError, DeviceResult};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RTLxDriver(Arc<Mutex<RTL8211F<ProviderImpl>>>);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RTLxInterface {
|
||||
pub iface: Arc<Mutex<Interface<'static, RTLxDriver>>>,
|
||||
pub driver: RTLxDriver,
|
||||
pub name: String,
|
||||
pub irq: usize,
|
||||
}
|
||||
|
||||
impl Scheme for RTLxInterface {
|
||||
fn name(&self) -> &str {
|
||||
"rtl8211f"
|
||||
}
|
||||
|
||||
fn handle_irq(&self, irq: usize) {
|
||||
if irq != self.irq {
|
||||
// not ours, skip it
|
||||
return;
|
||||
}
|
||||
|
||||
let status = self.driver.0.lock().interrupt_status();
|
||||
|
||||
let handle_tx_rx = 3;
|
||||
if status == handle_tx_rx {
|
||||
let timestamp = Instant::from_millis(0);
|
||||
let sockets = get_sockets();
|
||||
let mut sockets = sockets.lock();
|
||||
|
||||
self.driver.0.lock().int_disable();
|
||||
match self.iface.lock().poll(&mut sockets, timestamp) {
|
||||
Ok(b) => {
|
||||
debug!("nic poll, is changed ?: {}", b);
|
||||
}
|
||||
Err(err) => {
|
||||
error!("poll got err {}", err);
|
||||
}
|
||||
}
|
||||
self.driver.0.lock().int_enable();
|
||||
//return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetScheme for RTLxInterface {
|
||||
fn get_mac(&self) -> EthernetAddress {
|
||||
self.iface.lock().ethernet_addr()
|
||||
}
|
||||
|
||||
fn get_ifname(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
fn get_ip_address(&self) -> Vec<IpCidr> {
|
||||
Vec::from(self.iface.lock().ip_addrs())
|
||||
}
|
||||
|
||||
fn poll(&self) -> DeviceResult {
|
||||
let timestamp = Instant::from_millis(0);
|
||||
let sockets = get_sockets();
|
||||
let mut sockets = sockets.lock();
|
||||
match self.iface.lock().poll(&mut sockets, timestamp) {
|
||||
Ok(b) => {
|
||||
debug!("nic poll, is changed ?: {}", b);
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
error!("poll got err {}", err);
|
||||
Err(DeviceError::IoError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn recv(&self, buf: &mut [u8]) -> DeviceResult<usize> {
|
||||
if self.driver.0.lock().can_recv() {
|
||||
let (vec_recv, rxcount) = self.driver.0.lock().geth_recv(1);
|
||||
buf.copy_from_slice(&vec_recv);
|
||||
Ok(rxcount as usize)
|
||||
} else {
|
||||
Err(DeviceError::NotReady)
|
||||
}
|
||||
}
|
||||
|
||||
fn send(&self, data: &[u8]) -> DeviceResult<usize> {
|
||||
if self.driver.0.lock().can_send() {
|
||||
self.driver.0.lock().geth_send(data).unwrap();
|
||||
Ok(data.len())
|
||||
} else {
|
||||
Err(DeviceError::NotReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RTLxRxToken(Vec<u8>);
|
||||
pub struct RTLxTxToken(RTLxDriver);
|
||||
|
||||
impl<'a> Device<'a> for RTLxDriver {
|
||||
type RxToken = RTLxRxToken;
|
||||
type TxToken = RTLxTxToken;
|
||||
|
||||
fn capabilities(&self) -> DeviceCapabilities {
|
||||
let mut caps = DeviceCapabilities::default();
|
||||
caps.max_transmission_unit = 1536;
|
||||
caps.max_burst_size = Some(64);
|
||||
caps.medium = Medium::Ethernet;
|
||||
caps
|
||||
}
|
||||
|
||||
fn receive(&mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
||||
if self.0.lock().can_recv() {
|
||||
//这里每次只接收一个网络包
|
||||
let (vec_recv, _rxcount) = self.0.lock().geth_recv(1);
|
||||
Some((RTLxRxToken(vec_recv), RTLxTxToken(self.clone())))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn transmit(&mut self) -> Option<Self::TxToken> {
|
||||
if self.0.lock().can_send() {
|
||||
Some(RTLxTxToken(self.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl phy::RxToken for RTLxRxToken {
|
||||
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> Result<R>,
|
||||
{
|
||||
f(&mut self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl phy::TxToken for RTLxTxToken {
|
||||
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> Result<R>,
|
||||
{
|
||||
let mut buffer = [0u8; 1536];
|
||||
let result = f(&mut buffer[..len]);
|
||||
if result.is_ok() {
|
||||
(self.0).0.lock().geth_send(&buffer[..len]).unwrap();
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rtlx_init<F: Fn(usize, usize) -> Option<usize>>(
|
||||
irq: usize,
|
||||
mapper: F,
|
||||
) -> DeviceResult<RTLxInterface> {
|
||||
mapper(rtl8211f::PINCTRL_GPIO_BASE as usize, PAGE_SIZE * 2);
|
||||
mapper(rtl8211f::SYS_CFG_BASE as usize, PAGE_SIZE * 2);
|
||||
|
||||
let mut rtl8211f = RTL8211F::<ProviderImpl>::new(&[0u8; 6]);
|
||||
let mac = rtl8211f.get_umac();
|
||||
//启动前请为D1插上网线
|
||||
warn!("Please plug in the Ethernet cable");
|
||||
|
||||
rtl8211f.open().unwrap();
|
||||
rtl8211f.set_rx_mode();
|
||||
rtl8211f.adjust_link().unwrap();
|
||||
|
||||
let net_driver = RTLxDriver(Arc::new(Mutex::new(rtl8211f)));
|
||||
|
||||
let ethernet_addr = EthernetAddress::from_bytes(&mac);
|
||||
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 0, 123), 24)];
|
||||
let default_gateway = Ipv4Address::new(192, 168, 0, 1);
|
||||
static mut ROUTES_STORAGE: [Option<(IpCidr, Route)>; 1] = [None; 1];
|
||||
let mut routes = unsafe { Routes::new(&mut ROUTES_STORAGE[..]) };
|
||||
routes.add_default_ipv4_route(default_gateway).unwrap();
|
||||
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||
let iface = InterfaceBuilder::new(net_driver.clone())
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.ip_addrs(ip_addrs)
|
||||
.routes(routes)
|
||||
.finalize();
|
||||
|
||||
info!("rtl8211f interface up with addr 192.168.0.123/24");
|
||||
info!("rtl8211f interface up with route 192.168.0.1/24");
|
||||
let rtl8211f_iface = RTLxInterface {
|
||||
iface: Arc::new(Mutex::new(iface)),
|
||||
driver: net_driver,
|
||||
name: String::from("rtl8211f"),
|
||||
irq,
|
||||
};
|
||||
|
||||
Ok(rtl8211f_iface)
|
||||
}
|
||||
|
||||
//TODO: Global SocketSet
|
||||
// lazy_static::lazy_static! {
|
||||
// pub static ref SOCKETS: Mutex<SocketSet<'static>> =
|
||||
// Mutex::new(SocketSet::new(vec![]));
|
||||
// }
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
//! Re-export most commonly used driver types.
|
||||
|
||||
pub use crate::scheme::display::{ColorFormat, DisplayInfo, FrameBuffer, Rectangle, RgbColor};
|
||||
pub use crate::scheme::input::{CapabilityType, InputCapability, InputEvent, InputEventType};
|
||||
pub use crate::scheme::irq::{IrqHandler, IrqPolarity, IrqTriggerMode};
|
||||
pub use crate::{Device, DeviceError, DeviceResult};
|
||||
|
||||
/// Re-export types from [`input`](crate::input).
|
||||
pub mod input {
|
||||
pub use crate::input::{Mouse, MouseFlags, MouseState};
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
use super::Scheme;
|
||||
use crate::DeviceResult;
|
||||
|
||||
pub trait BlockScheme: Scheme {
|
||||
fn read_block(&self, block_id: usize, buf: &mut [u8]) -> DeviceResult;
|
||||
fn write_block(&self, block_id: usize, buf: &[u8]) -> DeviceResult;
|
||||
fn flush(&self) -> DeviceResult;
|
||||
}
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
use super::Scheme;
|
||||
use crate::DeviceResult;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct RgbColor(u32);
|
||||
|
||||
/// Color format for one pixel. `RGB888` means R in bits 16-23, G in bits 8-15 and B in bits 0-7.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ColorFormat {
|
||||
RGB332,
|
||||
RGB565,
|
||||
RGB888,
|
||||
ARGB8888,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Rectangle {
|
||||
pub x: u32,
|
||||
pub y: u32,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
pub struct FrameBuffer<'a> {
|
||||
raw: &'a mut [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct DisplayInfo {
|
||||
/// visible width
|
||||
pub width: u32,
|
||||
/// visible height
|
||||
pub height: u32,
|
||||
/// color encoding format of RGBA
|
||||
pub format: ColorFormat,
|
||||
/// frame buffer base virtual address
|
||||
pub fb_base_vaddr: usize,
|
||||
/// frame buffer size
|
||||
pub fb_size: usize,
|
||||
}
|
||||
|
||||
impl RgbColor {
|
||||
#[inline]
|
||||
pub const fn new(r: u8, g: u8, b: u8) -> Self {
|
||||
Self(((r as u32) << 16) | ((g as u32) << 8) | b as u32)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn r(self) -> u8 {
|
||||
(self.0 >> 16) as u8
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn g(self) -> u8 {
|
||||
(self.0 >> 8) as u8
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn b(self) -> u8 {
|
||||
self.0 as u8
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn raw_value(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorFormat {
|
||||
/// Number of bits per pixel.
|
||||
#[inline]
|
||||
pub const fn depth(self) -> u8 {
|
||||
match self {
|
||||
Self::RGB332 => 8,
|
||||
Self::RGB565 => 16,
|
||||
Self::RGB888 => 24,
|
||||
Self::ARGB8888 => 32,
|
||||
}
|
||||
}
|
||||
|
||||
/// Number of bytes per pixel.
|
||||
#[inline]
|
||||
pub const fn bytes(self) -> u8 {
|
||||
self.depth() / 8
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FrameBuffer<'a> {
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because it created the `FrameBuffer` structure
|
||||
/// from the raw pointer.
|
||||
pub unsafe fn from_raw_parts_mut(ptr: *mut u8, len: usize) -> Self {
|
||||
Self {
|
||||
raw: core::slice::from_raw_parts_mut(ptr, len),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_slice(slice: &'a mut [u8]) -> Self {
|
||||
Self { raw: slice }
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller must ensure `offset` does
|
||||
/// not exceed the frame buffer size.
|
||||
pub unsafe fn write_color(&mut self, offset: usize, color: RgbColor, format: ColorFormat) {
|
||||
const fn pack_channel(
|
||||
r_val: u8,
|
||||
_r_bits: u8,
|
||||
g_val: u8,
|
||||
g_bits: u8,
|
||||
b_val: u8,
|
||||
b_bits: u8,
|
||||
) -> u32 {
|
||||
((r_val as u32) << (g_bits + b_bits)) | ((g_val as u32) << b_bits) | b_val as u32
|
||||
}
|
||||
|
||||
let (r, g, b) = (color.r(), color.g(), color.b());
|
||||
let ptr = self.raw.as_mut_ptr().add(offset);
|
||||
let dst = core::slice::from_raw_parts_mut(ptr, 4);
|
||||
match format {
|
||||
ColorFormat::RGB332 => {
|
||||
*ptr = pack_channel(r >> (8 - 3), 3, g >> (8 - 3), 3, b >> (8 - 2), 2) as u8
|
||||
}
|
||||
ColorFormat::RGB565 => {
|
||||
*(ptr as *mut u16) =
|
||||
pack_channel(r >> (8 - 5), 5, g >> (8 - 6), 6, b >> (8 - 5), 5) as u16
|
||||
}
|
||||
ColorFormat::RGB888 => {
|
||||
dst[2] = r;
|
||||
dst[1] = g;
|
||||
dst[0] = b;
|
||||
}
|
||||
ColorFormat::ARGB8888 => *(ptr as *mut u32) = color.raw_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> core::ops::Deref for FrameBuffer<'a> {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.raw
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> core::ops::DerefMut for FrameBuffer<'a> {
|
||||
#[allow(clippy::needless_borrow)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.raw
|
||||
}
|
||||
}
|
||||
|
||||
impl DisplayInfo {
|
||||
/// Number of bytes between each row of the frame buffer.
|
||||
#[inline]
|
||||
pub const fn pitch(self) -> u32 {
|
||||
self.width * self.format.bytes() as u32
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DisplayScheme: Scheme {
|
||||
fn info(&self) -> DisplayInfo;
|
||||
|
||||
/// Returns the framebuffer.
|
||||
fn fb(&self) -> FrameBuffer;
|
||||
|
||||
/// Write pixel color.
|
||||
#[inline]
|
||||
fn draw_pixel(&self, x: u32, y: u32, color: RgbColor) {
|
||||
let info = self.info();
|
||||
let offset = (x + y * info.width) as usize * info.format.bytes() as usize;
|
||||
if offset < info.fb_size {
|
||||
unsafe { self.fb().write_color(offset, color, info.format) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill a given rectangle with `color`.
|
||||
fn fill_rect(&self, rect: &Rectangle, color: RgbColor) {
|
||||
let info = self.info();
|
||||
let left = rect.x.min(info.width);
|
||||
let right = (left + rect.width).min(info.width);
|
||||
let top = rect.y.min(info.height);
|
||||
let bottom = (top + rect.height).min(info.height);
|
||||
for j in top..bottom {
|
||||
for i in left..right {
|
||||
self.draw_pixel(i, j, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the screen with `color`.
|
||||
fn clear(&self, color: RgbColor) {
|
||||
let info = self.info();
|
||||
self.fill_rect(
|
||||
&Rectangle {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
},
|
||||
color,
|
||||
)
|
||||
}
|
||||
|
||||
/// Whether need to flush the frambuffer to screen.
|
||||
#[inline]
|
||||
fn need_flush(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Flush framebuffer to screen.
|
||||
#[inline]
|
||||
fn flush(&self) -> DeviceResult {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
use crate::utils::EventHandler;
|
||||
|
||||
pub trait EventScheme {
|
||||
type Event;
|
||||
|
||||
/// Trigger the event manually and call its handler immediately.
|
||||
fn trigger(&self, event: Self::Event);
|
||||
|
||||
/// Subscribe events, call the `handler` when an input event occurs.
|
||||
/// If `once` is ture, unsubscribe automatically after handling.
|
||||
fn subscribe(&self, handler: EventHandler<Self::Event>, once: bool);
|
||||
}
|
||||
|
||||
macro_rules! impl_event_scheme {
|
||||
($struct:ident $(, $event_ty:ty)?) => {
|
||||
impl_event_scheme!(@impl_base $struct $(, $event_ty)?);
|
||||
};
|
||||
($struct:ident<'_> $(, $event_ty:ty)?) => {
|
||||
impl_event_scheme!(@impl_base $struct<'_> $(, $event_ty)?);
|
||||
};
|
||||
($struct:ident < $($types:ident),* > $(where $($preds:tt)+)? $(, $event_ty:ty)?) => {
|
||||
impl_event_scheme!(@impl_base $struct < $($types),* > $(where $($preds)+)? $(, $event_ty)?);
|
||||
};
|
||||
|
||||
(@impl_base $struct:ident $(, $event_ty:ty)?) => {
|
||||
impl $crate::scheme::EventScheme for $struct {
|
||||
impl_event_scheme!(@impl_body $(, $event_ty)?);
|
||||
}
|
||||
};
|
||||
(@impl_base $struct:ident<'_> $(, $event_ty:ty)?) => {
|
||||
impl $crate::scheme::EventScheme for $struct<'_> {
|
||||
impl_event_scheme!(@impl_body $(, $event_ty)?);
|
||||
}
|
||||
};
|
||||
(@impl_base $struct:ident < $($types:ident),* > $(where $($preds:tt)+)? $(, $event_ty:ty)?) => {
|
||||
impl < $($types),* > $crate::scheme::EventScheme for $struct < $($types),* >
|
||||
$(where $($preds)+)?
|
||||
{
|
||||
impl_event_scheme!(@impl_body $(, $event_ty)?);
|
||||
}
|
||||
};
|
||||
|
||||
(@impl_assoc_type) => {
|
||||
type Event = ();
|
||||
};
|
||||
(@impl_assoc_type, $event_ty:ty) => {
|
||||
type Event = $event_ty;
|
||||
};
|
||||
(@impl_body $(, $event_ty:ty)?) => {
|
||||
impl_event_scheme!(@impl_assoc_type $(, $event_ty)?);
|
||||
|
||||
#[inline]
|
||||
fn trigger(&self, event: Self::Event) {
|
||||
self.listener.trigger(event);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn subscribe(&self, handler: $crate::utils::EventHandler<Self::Event>, once: bool) {
|
||||
self.listener.subscribe(handler, once);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
use core::fmt;
|
||||
|
||||
use super::{event::EventScheme, Scheme};
|
||||
use crate::input::input_event_codes::ev::*;
|
||||
|
||||
numeric_enum_macro::numeric_enum! {
|
||||
#[repr(u16)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
/// Linux input event codes.
|
||||
///
|
||||
/// Reference: <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input-event-codes.h>
|
||||
pub enum InputEventType {
|
||||
/// Used as markers to separate events. Events may be separated in time or in space,
|
||||
/// such as with the multitouch protocol.
|
||||
Syn = EV_SYN,
|
||||
/// Used to describe state changes of keyboards, buttons, or other key-like devices.
|
||||
Key = EV_KEY,
|
||||
/// Used to describe relative axis value changes, e.g. moving the mouse 5 units
|
||||
/// to the left.
|
||||
RelAxis = EV_REL,
|
||||
/// Used to describe absolute axis value changes, e.g. describing the coordinates
|
||||
/// of a touch on a touchscreen.
|
||||
AbsAxis = EV_ABS,
|
||||
/// Used to describe miscellaneous input data that do not fit into other types.
|
||||
Misc = EV_MSC,
|
||||
/// Used to describe binary state input switches.
|
||||
Switch = EV_SW,
|
||||
/// Used to turn LEDs on devices on and off.
|
||||
Led = EV_LED,
|
||||
/// Used to output sound to devices.
|
||||
Sound = EV_SND,
|
||||
/// Used for autorepeating devices.
|
||||
Repeat = EV_REP,
|
||||
/// Used to send force feedback commands to an input device.
|
||||
FeedBack = EV_FF,
|
||||
/// A special type for power button and switch input.
|
||||
Power = EV_PWR,
|
||||
/// Used to receive force feedback device status.
|
||||
FeedBackStatus = EV_FF_STATUS,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct InputEvent {
|
||||
pub event_type: InputEventType,
|
||||
pub code: u16,
|
||||
pub value: i32,
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CapabilityType {
|
||||
Key = EV_KEY,
|
||||
RelAxis = EV_REL,
|
||||
AbsAxis = EV_ABS,
|
||||
Misc = EV_MSC,
|
||||
Switch = EV_SW,
|
||||
Led = EV_LED,
|
||||
Sound = EV_SND,
|
||||
FeedBack = EV_FF,
|
||||
Event,
|
||||
InputProp,
|
||||
}
|
||||
|
||||
pub struct InputCapability {
|
||||
/// bitmap to support up to 1024 bits.
|
||||
bitmap: [u64; 16],
|
||||
}
|
||||
|
||||
impl InputCapability {
|
||||
pub fn empty() -> Self {
|
||||
Self { bitmap: [0; 16] }
|
||||
}
|
||||
|
||||
pub fn from_bitmap(bitmap: &[u8]) -> Self {
|
||||
let mut cap = Self::empty();
|
||||
let bitcount = bitmap.len() as u16 * 8;
|
||||
for i in 0..bitcount as usize {
|
||||
if bitmap[i / 8] & (1 << (i % 64)) != 0 {
|
||||
cap.set(i as u16);
|
||||
}
|
||||
}
|
||||
cap
|
||||
}
|
||||
|
||||
pub fn set(&mut self, code: u16) {
|
||||
self.bitmap[code as usize / 64] |= 1 << (code % 64);
|
||||
}
|
||||
|
||||
pub fn set_all(&mut self, codes: &[u16]) {
|
||||
for &c in codes {
|
||||
self.set(c);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains(&self, code: u16) -> bool {
|
||||
self.bitmap[code as usize / 64] & (1 << (code % 64)) != 0
|
||||
}
|
||||
|
||||
pub fn contains_all(&self, codes: &[u16]) -> bool {
|
||||
for &c in codes {
|
||||
if !self.contains(c) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for InputCapability {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut skip_empty = true;
|
||||
write!(f, "[")?;
|
||||
for i in (0..16).rev() {
|
||||
if self.bitmap[i] > 0 || !skip_empty {
|
||||
write!(f, "{:#016x}", self.bitmap[i])?;
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
skip_empty = false;
|
||||
}
|
||||
}
|
||||
write!(f, "]")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InputScheme: Scheme + EventScheme<Event = InputEvent> {
|
||||
/// Returns the capability bitmap of the specific kind of event.
|
||||
fn capability(&self, cap_type: CapabilityType) -> InputCapability;
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
use alloc::boxed::Box;
|
||||
use alloc::sync::Arc;
|
||||
use core::ops::Range;
|
||||
|
||||
use super::Scheme;
|
||||
use crate::DeviceResult;
|
||||
|
||||
/// A type alias for
|
||||
pub type IrqHandler = Box<dyn Fn() + Send + Sync>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IrqTriggerMode {
|
||||
Edge,
|
||||
Level,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IrqPolarity {
|
||||
ActiveHigh,
|
||||
ActiveLow,
|
||||
}
|
||||
|
||||
pub trait IrqScheme: Scheme {
|
||||
/// Is a valid IRQ number.
|
||||
fn is_valid_irq(&self, irq_num: usize) -> bool;
|
||||
|
||||
/// Disable IRQ.
|
||||
fn mask(&self, irq_num: usize) -> DeviceResult;
|
||||
|
||||
/// Enable IRQ.
|
||||
fn unmask(&self, irq_num: usize) -> DeviceResult;
|
||||
|
||||
/// Configure the specified interrupt vector. If it is invoked, it must be
|
||||
/// invoked prior to interrupt registration.
|
||||
fn configure(&self, _irq_num: usize, _tm: IrqTriggerMode, _pol: IrqPolarity) -> DeviceResult {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Add an interrupt handler to an IRQ.
|
||||
fn register_handler(&self, irq_num: usize, handler: IrqHandler) -> DeviceResult;
|
||||
|
||||
/// Register the device to delivery an IRQ.
|
||||
fn register_device(&self, irq_num: usize, dev: Arc<dyn Scheme>) -> DeviceResult {
|
||||
self.register_handler(irq_num, Box::new(move || dev.handle_irq(irq_num)))
|
||||
}
|
||||
|
||||
/// Remove the interrupt handler to an IRQ.
|
||||
fn unregister(&self, irq_num: usize) -> DeviceResult;
|
||||
|
||||
/// Method used for platform allocation of blocks of MSI and MSI-X compatible
|
||||
/// IRQ targets.
|
||||
fn msi_alloc_block(&self, _requested_irqs: usize) -> DeviceResult<Range<usize>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Method used to free a block of MSI IRQs previously allocated by msi_alloc_block().
|
||||
/// This does not unregister IRQ handlers.
|
||||
fn msi_free_block(&self, _block: Range<usize>) -> DeviceResult {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Register a handler function for a given msi_id within an msi_block_t. Passing a
|
||||
/// NULL handler will effectively unregister a handler for a given msi_id within the
|
||||
/// block.
|
||||
fn msi_register_handler(
|
||||
&self,
|
||||
_block: Range<usize>,
|
||||
_msi_id: usize,
|
||||
_handler: IrqHandler,
|
||||
) -> DeviceResult {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Init irq for current cpu.
|
||||
/// Some IRQ hardware requires per-CPU initialization.
|
||||
fn init_hart(&self) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// [for x86_64] enable apic timer
|
||||
fn apic_timer_enable(&self) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
//! The [`Scheme`] describe some functions must be implemented for different type of devices,
|
||||
//! there are many [`Scheme`] traits in this mod.
|
||||
//!
|
||||
//! If you need to develop a new device, just implement the corresponding trait.
|
||||
//!
|
||||
//! The [`Scheme`] trait is suitable for any architecture.
|
||||
|
||||
pub(super) mod block;
|
||||
pub(super) mod display;
|
||||
pub(super) mod input;
|
||||
pub(super) mod irq;
|
||||
pub(super) mod net;
|
||||
pub(super) mod uart;
|
||||
|
||||
#[macro_use]
|
||||
pub(super) mod event;
|
||||
pub(super) use impl_event_scheme;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
pub use block::BlockScheme;
|
||||
pub use display::DisplayScheme;
|
||||
pub use event::EventScheme;
|
||||
pub use input::InputScheme;
|
||||
pub use irq::IrqScheme;
|
||||
pub use net::NetScheme;
|
||||
pub use uart::UartScheme;
|
||||
|
||||
/// Common of all device drivers.
|
||||
///
|
||||
/// Every device must says its name and handles interrupts.
|
||||
pub trait Scheme: SchemeUpcast + Send + Sync {
|
||||
/// Returns name of the driver.
|
||||
fn name(&self) -> &str;
|
||||
|
||||
/// Handles an interrupt.
|
||||
fn handle_irq(&self, _irq_num: usize) {}
|
||||
}
|
||||
|
||||
/// Used to convert a concrete type pointer to a general [`Scheme`] pointer.
|
||||
pub trait SchemeUpcast {
|
||||
/// Performs the conversion.
|
||||
fn upcast<'a>(self: Arc<Self>) -> Arc<dyn Scheme + 'a>
|
||||
where
|
||||
Self: 'a;
|
||||
}
|
||||
|
||||
impl<T: Scheme + Sized> SchemeUpcast for T {
|
||||
fn upcast<'a>(self: Arc<Self>) -> Arc<dyn Scheme + 'a>
|
||||
where
|
||||
Self: 'a,
|
||||
{
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
use super::Scheme;
|
||||
use crate::DeviceResult;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use smoltcp::wire::{EthernetAddress, IpCidr};
|
||||
|
||||
pub trait NetScheme: Scheme {
|
||||
fn recv(&self, buf: &mut [u8]) -> DeviceResult<usize>;
|
||||
fn send(&self, buf: &[u8]) -> DeviceResult<usize>;
|
||||
fn get_mac(&self) -> EthernetAddress;
|
||||
fn get_ifname(&self) -> String;
|
||||
fn get_ip_address(&self) -> Vec<IpCidr>;
|
||||
fn poll(&self) -> DeviceResult;
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
use super::{event::EventScheme, Scheme};
|
||||
use crate::DeviceResult;
|
||||
|
||||
pub trait UartScheme: Scheme + EventScheme<Event = ()> {
|
||||
fn try_recv(&self) -> DeviceResult<Option<u8>>;
|
||||
fn send(&self, ch: u8) -> DeviceResult;
|
||||
fn write_str(&self, s: &str) -> DeviceResult {
|
||||
for c in s.bytes() {
|
||||
self.send(c)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
use alloc::{boxed::Box, collections::VecDeque, string::String, sync::Arc};
|
||||
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
|
||||
use crate::utils::EventListener;
|
||||
use crate::DeviceResult;
|
||||
|
||||
const BUF_CAPACITY: usize = 4096;
|
||||
|
||||
pub struct BufferedUart {
|
||||
inner: Arc<dyn UartScheme>,
|
||||
buf: Mutex<VecDeque<u8>>,
|
||||
listener: EventListener,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl_event_scheme!(BufferedUart);
|
||||
|
||||
impl BufferedUart {
|
||||
pub fn new(uart: Arc<dyn UartScheme>) -> Arc<Self> {
|
||||
let ret = Arc::new(Self {
|
||||
inner: uart.clone(),
|
||||
name: alloc::format!("{}-buffered", uart.name()),
|
||||
buf: Mutex::new(VecDeque::with_capacity(BUF_CAPACITY)),
|
||||
listener: EventListener::new(),
|
||||
});
|
||||
let cloned = ret.clone();
|
||||
uart.subscribe(Box::new(move |_| cloned.handle_irq(0)), false);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheme for BufferedUart {
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
fn handle_irq(&self, _unused: usize) {
|
||||
while let Some(c) = self.inner.try_recv().unwrap_or(None) {
|
||||
let mut buf = self.buf.lock();
|
||||
if buf.len() < BUF_CAPACITY {
|
||||
let c = if c == b'\r' { b'\n' } else { c };
|
||||
buf.push_back(c);
|
||||
}
|
||||
}
|
||||
if self.buf.lock().len() > 0 {
|
||||
self.listener.trigger(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UartScheme for BufferedUart {
|
||||
fn try_recv(&self) -> DeviceResult<Option<u8>> {
|
||||
Ok(self.buf.lock().pop_front())
|
||||
}
|
||||
fn send(&self, ch: u8) -> DeviceResult {
|
||||
self.inner.send(ch)
|
||||
}
|
||||
fn write_str(&self, s: &str) -> DeviceResult {
|
||||
self.inner.write_str(s)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
//! Uart device driver.
|
||||
|
||||
mod buffered;
|
||||
mod uart_16550;
|
||||
|
||||
pub use buffered::BufferedUart;
|
||||
pub use uart_16550::Uart16550Mmio;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use uart_16550::Uart16550Pmio;
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
use core::convert::TryInto;
|
||||
use core::ops::{BitAnd, BitOr, Not};
|
||||
|
||||
use bitflags::bitflags;
|
||||
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! {
|
||||
/// Interrupt enable flags
|
||||
struct IntEnFlags: u8 {
|
||||
const RECEIVED = 1;
|
||||
const SENT = 1 << 1;
|
||||
const ERRORED = 1 << 2;
|
||||
const STATUS_CHANGE = 1 << 3;
|
||||
// 4 to 7 are unused
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Line status flags
|
||||
struct LineStsFlags: u8 {
|
||||
const INPUT_FULL = 1;
|
||||
// 1 to 4 unknown
|
||||
const OUTPUT_EMPTY = 1 << 5;
|
||||
// 6 and 7 unknown
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Uart16550Inner<T: Io> {
|
||||
/// Data register, read to receive, write to send
|
||||
data: T,
|
||||
/// Interrupt enable
|
||||
int_en: T,
|
||||
/// FIFO control
|
||||
fifo_ctrl: T,
|
||||
/// Line control
|
||||
line_ctrl: T,
|
||||
/// Modem control
|
||||
modem_ctrl: T,
|
||||
/// Line status
|
||||
line_sts: ReadOnly<T>,
|
||||
/// Modem status
|
||||
modem_sts: ReadOnly<T>,
|
||||
}
|
||||
|
||||
impl<T: Io> Uart16550Inner<T>
|
||||
where
|
||||
T::Value: From<u8> + TryInto<u8>,
|
||||
{
|
||||
fn init(&mut self) {
|
||||
// Disable interrupts
|
||||
self.int_en.write(0x00.into());
|
||||
|
||||
// Enable FIFO, clear TX/RX queues and
|
||||
// set interrupt watermark at 14 bytes
|
||||
self.fifo_ctrl.write(0xC7.into());
|
||||
|
||||
// Mark data terminal ready, signal request to send
|
||||
// and enable auxilliary output #2 (used as interrupt line for CPU)
|
||||
self.modem_ctrl.write(0x0B.into());
|
||||
|
||||
// Enable interrupts
|
||||
self.int_en.write(0x01.into());
|
||||
}
|
||||
|
||||
fn line_sts(&self) -> LineStsFlags {
|
||||
LineStsFlags::from_bits_truncate(
|
||||
(self.line_sts.read() & 0xFF.into()).try_into().unwrap_or(0),
|
||||
)
|
||||
}
|
||||
|
||||
fn try_recv(&mut self) -> DeviceResult<Option<u8>> {
|
||||
if self.line_sts().contains(LineStsFlags::INPUT_FULL) {
|
||||
Ok(Some(
|
||||
(self.data.read() & 0xFF.into()).try_into().unwrap_or(0),
|
||||
))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn send(&mut self, ch: u8) -> DeviceResult {
|
||||
while !self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
|
||||
self.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 Uart16550Mmio<V: 'static>
|
||||
where
|
||||
V: Copy + BitAnd<Output = V> + BitOr<Output = V> + Not<Output = V>,
|
||||
{
|
||||
inner: Mutex<&'static mut Uart16550Inner<Mmio<V>>>,
|
||||
listener: EventListener,
|
||||
}
|
||||
|
||||
impl_event_scheme!(Uart16550Mmio<V>
|
||||
where
|
||||
V: Copy
|
||||
+ BitAnd<Output = V>
|
||||
+ BitOr<Output = V>
|
||||
+ Not<Output = V>
|
||||
+ From<u8>
|
||||
+ TryInto<u8>
|
||||
+ Send
|
||||
);
|
||||
|
||||
impl<V> Scheme for Uart16550Mmio<V>
|
||||
where
|
||||
V: Copy + BitAnd<Output = V> + BitOr<Output = V> + Not<Output = V> + Send,
|
||||
{
|
||||
fn name(&self) -> &str {
|
||||
"uart16550-mmio"
|
||||
}
|
||||
|
||||
fn handle_irq(&self, _irq_num: usize) {
|
||||
self.listener.trigger(());
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> UartScheme for Uart16550Mmio<V>
|
||||
where
|
||||
V: Copy
|
||||
+ BitAnd<Output = V>
|
||||
+ BitOr<Output = V>
|
||||
+ Not<Output = V>
|
||||
+ From<u8>
|
||||
+ TryInto<u8>
|
||||
+ 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> Uart16550Mmio<V>
|
||||
where
|
||||
V: Copy
|
||||
+ BitAnd<Output = V>
|
||||
+ BitOr<Output = V>
|
||||
+ Not<Output = V>
|
||||
+ From<u8>
|
||||
+ TryInto<u8>
|
||||
+ Send,
|
||||
{
|
||||
unsafe fn new_common(base: usize) -> Self {
|
||||
let uart: &mut Uart16550Inner<Mmio<V>> = Mmio::<V>::from_base_as(base);
|
||||
uart.init();
|
||||
Self {
|
||||
inner: Mutex::new(uart),
|
||||
listener: EventListener::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Uart16550Mmio<u8> {
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because `base_addr` may be an arbitrary address.
|
||||
pub unsafe fn new(base: usize) -> Self {
|
||||
Self::new_common(base)
|
||||
}
|
||||
}
|
||||
|
||||
impl Uart16550Mmio<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)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod pmio {
|
||||
use super::*;
|
||||
use crate::io::Pmio;
|
||||
|
||||
/// Pmio driver for UART 16550
|
||||
pub struct Uart16550Pmio {
|
||||
inner: Mutex<Uart16550Inner<Pmio<u8>>>,
|
||||
listener: EventListener,
|
||||
}
|
||||
|
||||
impl_event_scheme!(Uart16550Pmio);
|
||||
|
||||
impl Scheme for Uart16550Pmio {
|
||||
fn name(&self) -> &str {
|
||||
"uart16550-Pmio"
|
||||
}
|
||||
|
||||
fn handle_irq(&self, _irq_num: usize) {
|
||||
self.listener.trigger(());
|
||||
}
|
||||
}
|
||||
|
||||
impl UartScheme for Uart16550Pmio {
|
||||
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 Uart16550Pmio {
|
||||
/// Construct a `Uart16550Pmio` whose address starts at `base`.
|
||||
pub fn new(base: u16) -> Self {
|
||||
let mut uart = Uart16550Inner::<Pmio<u8>> {
|
||||
data: Pmio::new(base),
|
||||
int_en: Pmio::new(base + 1),
|
||||
fifo_ctrl: Pmio::new(base + 2),
|
||||
line_ctrl: Pmio::new(base + 3),
|
||||
modem_ctrl: Pmio::new(base + 4),
|
||||
line_sts: ReadOnly::new(Pmio::new(base + 5)),
|
||||
modem_sts: ReadOnly::new(Pmio::new(base + 6)),
|
||||
};
|
||||
uart.init();
|
||||
Self {
|
||||
inner: Mutex::new(uart),
|
||||
listener: EventListener::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use pmio::Uart16550Pmio;
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
//! Package of [`device_tree`].
|
||||
|
||||
use crate::{DeviceError, DeviceResult, PhysAddr, VirtAddr};
|
||||
use alloc::vec::Vec;
|
||||
use core::ops::Range;
|
||||
use device_tree::{DeviceTree as DeviceTreeInner, PropError};
|
||||
|
||||
pub use device_tree::{util::StringList, Node};
|
||||
|
||||
/// A unified representation of the `interrupts` and `interrupts_extended`
|
||||
/// properties for any interrupt generating device.
|
||||
pub type InterruptsProp = Vec<u32>;
|
||||
|
||||
/// A wrapper structure of `device_tree::DeviceTree`.
|
||||
pub struct Devicetree(DeviceTreeInner);
|
||||
|
||||
/// Some properties inherited from ancestor nodes.
|
||||
///
|
||||
/// About the notion: cell, see <https://elinux.org/Device_Tree_Usage#How_Addressing_Works>.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct InheritProps {
|
||||
/// The `#address-cells` property of its parent node.
|
||||
pub parent_address_cells: u32,
|
||||
/// The `#size-cells` property of its parent node.
|
||||
pub parent_size_cells: u32,
|
||||
/// The `interrupt-parent` property of the node. If don't have, inherit from
|
||||
/// its parent node.
|
||||
pub interrupt_parent: u32,
|
||||
}
|
||||
|
||||
impl Devicetree {
|
||||
/// Load the device tree blob from the given virtual address.
|
||||
pub fn from(dtb_base_vaddr: VirtAddr) -> DeviceResult<Self> {
|
||||
match unsafe { DeviceTreeInner::load_from_raw_pointer(dtb_base_vaddr as *const _) } {
|
||||
Ok(dt) => Ok(Self(dt)),
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"device-tree: failed to load DTB @ {:#x}: {:?}",
|
||||
dtb_base_vaddr, err
|
||||
);
|
||||
Err(DeviceError::InvalidParam)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_inner<F>(&self, node: &Node, props: InheritProps, device_node_op: &mut F)
|
||||
where
|
||||
F: FnMut(&Node, &StringList, &InheritProps),
|
||||
{
|
||||
let mut props = props;
|
||||
if let Ok(num) = node.prop_u32("interrupt-parent") {
|
||||
props.interrupt_parent = num;
|
||||
}
|
||||
if let Ok(comp) = node.prop_str_list("compatible") {
|
||||
device_node_op(node, &comp, &props);
|
||||
}
|
||||
|
||||
props.parent_address_cells = node.prop_u32("#address-cells").unwrap_or(0);
|
||||
props.parent_size_cells = node.prop_u32("#size-cells").unwrap_or(0);
|
||||
|
||||
// DFS
|
||||
for child in node.children.iter() {
|
||||
self.walk_inner(child, props, device_node_op);
|
||||
}
|
||||
}
|
||||
|
||||
/// Traverse the tree from root by DFS, collect necessary properties, and
|
||||
/// apply the `device_node_op` to each node.
|
||||
pub fn walk<F>(&self, device_node_op: &mut F)
|
||||
where
|
||||
F: FnMut(&Node, &StringList, &InheritProps),
|
||||
{
|
||||
self.walk_inner(&self.0.root, InheritProps::default(), device_node_op)
|
||||
}
|
||||
|
||||
/// Returns the `bootargs` property in the `/chosen` node, as the kernel
|
||||
/// command line.
|
||||
pub fn bootargs(&self) -> Option<&str> {
|
||||
self.0.find("/chosen")?.prop_str("bootargs").ok()
|
||||
}
|
||||
|
||||
/// Returns the `timebase-frequency` property in the `/cpus` node, as timer
|
||||
pub fn timebase_frequency(&self) -> Option<u32> {
|
||||
self.0.find("/cpus")?.prop_u32("timebase-frequency").ok()
|
||||
}
|
||||
|
||||
/// Returns the `linux,initrd-start` and `linux,initrd-end` properties in
|
||||
/// the `/chosen` node, as the init RAM disk address region.
|
||||
pub fn initrd_region(&self) -> Option<Range<PhysAddr>> {
|
||||
let chosen = self.0.find("/chosen")?;
|
||||
let start = chosen.prop_u32("linux,initrd-start").ok()? as _;
|
||||
let end = chosen.prop_u32("linux,initrd-end").ok()? as _;
|
||||
Some(start..end)
|
||||
}
|
||||
|
||||
/// Returns the physical memory regions specified in the `/memory` nodes.
|
||||
pub fn memory_regions(&self) -> DeviceResult<Vec<Range<PhysAddr>>> {
|
||||
let props = InheritProps {
|
||||
parent_address_cells: self.0.root.prop_u32("#address-cells").unwrap_or(0),
|
||||
parent_size_cells: self.0.root.prop_u32("#size-cells").unwrap_or(0),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut regions = Vec::new();
|
||||
for node in &self.0.root.children {
|
||||
if node.name.starts_with("memory@")
|
||||
|| node.prop_str("device_type").unwrap_or_default() == "memory"
|
||||
{
|
||||
let (addr, size) = parse_reg(node, &props)?;
|
||||
regions.push(addr as usize..addr as usize + size as usize)
|
||||
}
|
||||
}
|
||||
Ok(regions)
|
||||
}
|
||||
}
|
||||
|
||||
/// Combine `cell_num` of 32-bit integers from `cells` into a 64-bit integer.
|
||||
fn from_cells(cells: &[u32], cell_num: u32) -> DeviceResult<u64> {
|
||||
if cell_num as usize > cells.len() {
|
||||
return Err(DeviceError::InvalidParam);
|
||||
}
|
||||
let mut value = 0;
|
||||
for &c in &cells[..cell_num as usize] {
|
||||
value = value << 32 | c as u64;
|
||||
}
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Parse the `reg` property, about `reg`: <https://elinux.org/Device_Tree_Usage#How_Addressing_Works>.
|
||||
pub fn parse_reg(node: &Node, props: &InheritProps) -> DeviceResult<(u64, u64)> {
|
||||
let cells = node.prop_cells("reg")?;
|
||||
let addr = from_cells(&cells, props.parent_address_cells)?;
|
||||
let size = from_cells(
|
||||
&cells[props.parent_address_cells as usize..],
|
||||
props.parent_size_cells,
|
||||
)?;
|
||||
Ok((addr, size))
|
||||
}
|
||||
|
||||
/// Returns a `Vec<u32>` according to the `interrupts` or `interrupts-extended`
|
||||
/// property, the first element is the interrupt parent.
|
||||
pub fn parse_interrupts(node: &Node, props: &InheritProps) -> DeviceResult<InterruptsProp> {
|
||||
if node.has_prop("interrupts-extended") {
|
||||
Ok(node.prop_cells("interrupts-extended")?)
|
||||
} else if node.has_prop("interrupts") && props.interrupt_parent > 0 {
|
||||
let mut ret = node.prop_cells("interrupts")?;
|
||||
ret.insert(0, props.interrupt_parent);
|
||||
Ok(ret)
|
||||
} else {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PropError> for DeviceError {
|
||||
fn from(_err: PropError) -> Self {
|
||||
Self::InvalidParam
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue