forked from rcore-os/zCore
Compare commits
258 Commits
riscv-patc
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
d74dfad991 | |
|
|
b9e13aaab1 | |
|
|
6d951829b6 | |
|
|
6ab43eb9d8 | |
|
|
0f1ea71bfb | |
|
|
3daccb7e42 | |
|
|
00b10bd880 | |
|
|
42eb5c0708 | |
|
|
0aa57d8021 | |
|
|
b67cbc2398 | |
|
|
302ecf1990 | |
|
|
0e984e9777 | |
|
|
6ef8dc7a59 | |
|
|
f1ffe1d60e | |
|
|
bba9878981 | |
|
|
19f5cf712f | |
|
|
6b30fe8b40 | |
|
|
3b9b255ec9 | |
|
|
181b577cae | |
|
|
e41bf17a84 | |
|
|
c3ab0d38c4 | |
|
|
19bc2b7991 | |
|
|
13fb9eebbc | |
|
|
4dd51126b6 | |
|
|
939b6395c5 | |
|
|
f542b3cc6f | |
|
|
1e74f6a988 | |
|
|
794c807e34 | |
|
|
6f4dfd7273 | |
|
|
e1de630c4f | |
|
|
6749cd5179 | |
|
|
3fcc1f42f3 | |
|
|
3b706cf262 | |
|
|
9d8316b9b6 | |
|
|
f2aaa8d8f6 | |
|
|
134a31f0c3 | |
|
|
3d0186d95e | |
|
|
ebd4de4682 | |
|
|
9490e5d7a8 | |
|
|
b6bca47e94 | |
|
|
0f658c8158 | |
|
|
72c2191039 | |
|
|
6ba9602e8f | |
|
|
7de17ef115 | |
|
|
922312a430 | |
|
|
fa155fe95b | |
|
|
e70eecb5ba | |
|
|
64bf09c596 | |
|
|
9f991c6b4c | |
|
|
b8f66237d7 | |
|
|
359066bd89 | |
|
|
0fd2263a46 | |
|
|
35306f14c1 | |
|
|
55cc6438f7 | |
|
|
0b6aa1f958 | |
|
|
c55c72de43 | |
|
|
05bd6b0943 | |
|
|
3434c151a7 | |
|
|
cfb86710f4 | |
|
|
26912df809 | |
|
|
74f7a23bd6 | |
|
|
e4c1b8a397 | |
|
|
207449af67 | |
|
|
e3fa672f59 | |
|
|
8b36294ffe | |
|
|
77ff4eafeb | |
|
|
803bbd9962 | |
|
|
cf4629ec9d | |
|
|
0afb263958 | |
|
|
ce199ad9a7 | |
|
|
04ab8a380b | |
|
|
f4d395500d | |
|
|
8947cecf3c | |
|
|
231f1a1266 | |
|
|
eeb318cc9a | |
|
|
7c9abada74 | |
|
|
261344d381 | |
|
|
fee725d5f9 | |
|
|
6e29f418f9 | |
|
|
bb7604c434 | |
|
|
2f7685f23a | |
|
|
9f878044c9 | |
|
|
d9531cec75 | |
|
|
c72952df94 | |
|
|
5d93a4dbee | |
|
|
c309b03d08 | |
|
|
f5efe3b8c4 | |
|
|
6fb1f20f97 | |
|
|
c307eb8620 | |
|
|
42f2f0affb | |
|
|
0af4593e45 | |
|
|
e239d7ceb5 | |
|
|
1688fd9651 | |
|
|
e67a7301e3 | |
|
|
ef6c6adf37 | |
|
|
cfca262b55 | |
|
|
ca19f4fa8f | |
|
|
33f9ec9333 | |
|
|
51af7f4ed1 | |
|
|
4e3b53469c | |
|
|
5af92cb723 | |
|
|
ecea18fe1f | |
|
|
909765bfb2 | |
|
|
2ea758a810 | |
|
|
b3b113bc00 | |
|
|
4f6e3b2a50 | |
|
|
0181726f14 | |
|
|
aa86a412cd | |
|
|
1efacbffc9 | |
|
|
4711359b38 | |
|
|
fdd852abfc | |
|
|
42d7540439 | |
|
|
9bad3e20d2 | |
|
|
84b4143d45 | |
|
|
5741f12e5f | |
|
|
010f316a22 | |
|
|
fde18af386 | |
|
|
e9b863b59d | |
|
|
3544db899f | |
|
|
b1c89d7cfe | |
|
|
0fc50e5996 | |
|
|
0b390fd825 | |
|
|
e78ead64ee | |
|
|
c59d6aa88c | |
|
|
1750123a36 | |
|
|
0a4f6dbf38 | |
|
|
b51c8ebea3 | |
|
|
3734039a5e | |
|
|
55299ff1da | |
|
|
b1eb0c8d64 | |
|
|
b700eec2d6 | |
|
|
d2bc0b5fb7 | |
|
|
b052a9666b | |
|
|
8497aeea23 | |
|
|
4746413d3a | |
|
|
565abc371d | |
|
|
b3efbcfe09 | |
|
|
59c6de2d74 | |
|
|
a191f57ff3 | |
|
|
296766831a | |
|
|
e3066c23ae | |
|
|
08ab919633 | |
|
|
7a35b4fd5c | |
|
|
4d346d263e | |
|
|
dd3f2790e9 | |
|
|
5d3c254f47 | |
|
|
4028d6cb1a | |
|
|
c1e5bc0897 | |
|
|
cd0f4ee40d | |
|
|
028ecea082 | |
|
|
7b7911a2dc | |
|
|
980ccb164c | |
|
|
7eff7cf67b | |
|
|
0d1da32724 | |
|
|
2cb5d05b9a | |
|
|
2cb5cae22b | |
|
|
861bac0498 | |
|
|
7deff3e73b | |
|
|
0a28678a9f | |
|
|
5389c418fa | |
|
|
16206b1a52 | |
|
|
d585b87b09 | |
|
|
dbbde19546 | |
|
|
689a43fc30 | |
|
|
de77f11988 | |
|
|
3b8eaa17be | |
|
|
d8e4efad25 | |
|
|
008175ce2b | |
|
|
fa16615683 | |
|
|
99f21ba488 | |
|
|
41a0ce76d2 | |
|
|
3e165fe444 | |
|
|
2888c273b2 | |
|
|
a266160212 | |
|
|
8b6f0c0e00 | |
|
|
9156ebc6dd | |
|
|
3c1e8f66a3 | |
|
|
9caed02182 | |
|
|
767e9dd745 | |
|
|
d6687d9a65 | |
|
|
65eec60ac6 | |
|
|
a55017a967 | |
|
|
fcc46ebfc5 | |
|
|
06579b597f | |
|
|
cc9e06fc16 | |
|
|
9961dba5e2 | |
|
|
6e1cc2297d | |
|
|
8cc8898de2 | |
|
|
25a389f06a | |
|
|
9358545f1e | |
|
|
98a85ae9cb | |
|
|
3f3d5e2acc | |
|
|
b32d71b71c | |
|
|
a6e227aa1f | |
|
|
4cddebe2be | |
|
|
91a23d3f09 | |
|
|
69587e8049 | |
|
|
297a95d0d4 | |
|
|
0d5602bca0 | |
|
|
c9d90f97de | |
|
|
92fca7a6a6 | |
|
|
090b6af383 | |
|
|
202f6296b2 | |
|
|
4793db27ea | |
|
|
b517f543f8 | |
|
|
a32e503498 | |
|
|
d7a9741f06 | |
|
|
0bf5b1dc6c | |
|
|
c565c3299f | |
|
|
491694989c | |
|
|
4276b63ef4 | |
|
|
3cc3374c87 | |
|
|
5783d60f9b | |
|
|
f8bd0ae4a2 | |
|
|
974c5a887a | |
|
|
8038eee630 | |
|
|
bfe7339816 | |
|
|
3559a39b1f | |
|
|
497a70d15a | |
|
|
f5f2a6aedc | |
|
|
25402e96ee | |
|
|
c46f80c8eb | |
|
|
6fc573cec8 | |
|
|
682d274998 | |
|
|
5b8c17cc2e | |
|
|
3bfdae5cac | |
|
|
e01dd6973f | |
|
|
04f018d198 | |
|
|
9916e19a83 | |
|
|
d13f66b7f3 | |
|
|
51b305d27f | |
|
|
32fab8b318 | |
|
|
770242c7e9 | |
|
|
1f387b745b | |
|
|
b573dec4d7 | |
|
|
75faf43872 | |
|
|
00e5a49b60 | |
|
|
8770e25478 | |
|
|
56c29d7c28 | |
|
|
cd4476faec | |
|
|
e4de7167c5 | |
|
|
d90b5780c2 | |
|
|
afc4951b23 | |
|
|
e9a417963c | |
|
|
d6d80b0bf6 | |
|
|
596a8a7c5f | |
|
|
1e5992690d | |
|
|
e153f5713e | |
|
|
8278dc13b3 | |
|
|
47612fd312 | |
|
|
d410fde88a | |
|
|
0ecd206d6f | |
|
|
f450d37021 | |
|
|
eec570837d | |
|
|
a983b14f06 | |
|
|
d3ec807ae0 | |
|
|
d7a86f331c | |
|
|
f4983a8a2e |
|
|
@ -0,0 +1,16 @@
|
|||
[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"
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
cat > target/doc/index.html << EOF
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0;URL=kernel_hal/index.html">
|
||||
<title>Redirection</title>
|
||||
</head>
|
||||
<body onload="window.location = 'kernel_hal/index.html'">
|
||||
<p>Redirecting to <a href="kernel_hal/index.html">kernel_hal/index.html</a>...</p>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y $@
|
||||
pip3 install -r tests/requirements.txt
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/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
|
||||
|
|
@ -6,65 +6,58 @@ on:
|
|||
schedule:
|
||||
- cron: '0 22 * * *' # every day at 22:00 UTC
|
||||
|
||||
env:
|
||||
rust_toolchain: nightly-2022-01-20
|
||||
|
||||
jobs:
|
||||
check:
|
||||
workspace:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
override: true
|
||||
components: rust-src, rustfmt, clippy
|
||||
- name: Check code format
|
||||
run: cargo fmt --all -- --check
|
||||
- name: Clippy LibOS
|
||||
run: cargo clippy --all-features
|
||||
- name: Clippy x86_64 bare-metal
|
||||
run: cd zCore && make clippy ARCH=x86_64
|
||||
- name: Clippy riscv64 bare-metal
|
||||
run: cd zCore && make clippy ARCH=riscv64 LINUX=1
|
||||
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check format
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- uses: actions-rs/toolchain@v1
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
components: rust-src, llvm-tools-preview
|
||||
- uses: actions-rs/install@v0.1
|
||||
command: build
|
||||
args: --all-features
|
||||
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
crate: cargo-binutils
|
||||
version: latest
|
||||
- name: Build all packages
|
||||
run: cargo build
|
||||
- name: Build linux LibOS
|
||||
run: cargo build --features "linux libos"
|
||||
- name: Build zircon LibOS
|
||||
run: cargo build --features "zircon libos"
|
||||
- name: Build x86_64 bare-metal
|
||||
run: cd zCore && make build ARCH=x86_64
|
||||
- name: Build riscv64 bare-metal
|
||||
run: cd zCore && make build ARCH=riscv64 LINUX=1
|
||||
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@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
override: true
|
||||
target: aarch64-unknown-linux-gnu
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
|
|
@ -72,25 +65,85 @@ jobs:
|
|||
args: --target aarch64-unknown-linux-gnu --workspace --exclude linux-syscall --exclude zcore-loader --exclude zcore
|
||||
|
||||
build-user:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-latest]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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: nightly-2022-01-20
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
target: x86_64-fuchsia
|
||||
|
||||
- name: Build Zircon user programs
|
||||
run: cd zircon-user && make build MODE=release
|
||||
|
||||
build-doc:
|
||||
runs-on: ubuntu-20.04
|
||||
test-libos:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
mode: [linux, zircon]
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build docs
|
||||
run: cargo doc --no-deps --all-features
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -4,25 +4,25 @@ on:
|
|||
push:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
rust_toolchain: nightly-2022-01-20
|
||||
|
||||
jobs:
|
||||
doc:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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
|
||||
cat >target/doc/index.html <<EOF
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0;URL=kernel_hal/index.html">
|
||||
<title>Redirection</title>
|
||||
</head>
|
||||
<body onload="window.location = 'kernel_hal/index.html'">
|
||||
<p>Redirecting to <a href="kernel_hal/index.html">kernel_hal/index.html</a>...</p>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
.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
|
||||
|
|
|
|||
|
|
@ -6,26 +6,39 @@ on:
|
|||
schedule:
|
||||
- cron: '0 22 * * *' # every day at 22:00 UTC
|
||||
|
||||
env:
|
||||
rust_toolchain: nightly-2022-01-20
|
||||
qemu_version: 7.0.0
|
||||
|
||||
jobs:
|
||||
test:
|
||||
unit-test:
|
||||
name: Unit Test
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Pull prebuilt images
|
||||
run: git lfs pull -I prebuilt/linux/libc-libos.so,prebuilt/zircon/x64/bringup.zbi,prebuilt/zircon/x64/libzircon-libos.so,prebuilt/zircon/x64/userboot-libos.so
|
||||
- name: Prepare rootfs
|
||||
run: make rootfs
|
||||
- name: Test
|
||||
run: cargo test --no-fail-fast
|
||||
- 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@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-grcov
|
||||
|
||||
- name: Gather coverage data
|
||||
id: coverage
|
||||
uses: actions-rs/grcov@v0.1
|
||||
|
|
@ -36,142 +49,233 @@ jobs:
|
|||
# github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# path-to-lcov: ${{ steps.coverage.outputs.report }}
|
||||
|
||||
bench:
|
||||
bench-test:
|
||||
name: Bench Test
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run benchmarks
|
||||
run: cargo bench
|
||||
- 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@v2
|
||||
- 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,prebuilt/zircon/x64/libzircon-libos.so,prebuilt/zircon/x64/userboot-libos.so
|
||||
- name: Install dependencies
|
||||
run: pip3 install -r tests/requirements.txt
|
||||
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
|
||||
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
|
||||
|
||||
zircon-core-test-baremetal:
|
||||
linux-libc-test-libos:
|
||||
name: Linux Libc Test Libos
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x86_64]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Pull prebuilt images
|
||||
run: git lfs pull -I prebuilt/zircon/x64/core-tests.zbi,prebuilt/zircon/x64/libzircon.so,prebuilt/zircon/x64/userboot.so
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
components: rust-src
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install ninja-build -y
|
||||
pip3 install -r tests/requirements.txt
|
||||
- name: Cache QEMU
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: qemu-6.1.0
|
||||
key: qemu-6.1.0-${{ matrix.arch }}
|
||||
- name: Install QEMU
|
||||
run: |
|
||||
[ ! -d qemu-6.1.0 ] && wget https://download.qemu.org/qemu-6.1.0.tar.xz \
|
||||
&& tar xJf qemu-6.1.0.tar.xz > /dev/null \
|
||||
&& cd qemu-6.1.0 && ./configure --target-list=${{ matrix.arch }}-softmmu && cd ..
|
||||
cd qemu-6.1.0 && sudo make install -j
|
||||
qemu-system-${{ matrix.arch }} --version
|
||||
- name: Run fast tests
|
||||
if: github.event_name != 'schedule'
|
||||
run: cd tests && python3 zircon_core_test.py --fast
|
||||
- name: Run full tests
|
||||
if: github.event_name == 'schedule'
|
||||
run: cd tests && python3 zircon_core_test.py
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
|
||||
linux-libc-test-libos:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Pull prebuilt images
|
||||
run: git lfs pull -I prebuilt/linux/libc-libos.so
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install musl-tools musl-dev -y
|
||||
pip3 install -r tests/requirements.txt
|
||||
run: .github/scripts/install-deps.sh musl-tools musl-dev
|
||||
|
||||
- name: Prepare rootfs
|
||||
run: make rootfs && make libc-test
|
||||
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@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Pull prebuilt images
|
||||
run: git lfs pull -I prebuilt/linux/libc-libos.so
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
components: rust-src, llvm-tools-preview
|
||||
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: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install musl-tools musl-dev ninja-build -y
|
||||
pip3 install -r tests/requirements.txt
|
||||
run: .github/scripts/install-deps.sh musl-tools musl-dev ninja-build
|
||||
|
||||
- name: Cache QEMU
|
||||
uses: actions/cache@v1
|
||||
id: cache-qemu
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: qemu-6.1.0
|
||||
key: qemu-6.1.0-${{ matrix.arch }}
|
||||
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: |
|
||||
[ ! -d qemu-6.1.0 ] && wget https://download.qemu.org/qemu-6.1.0.tar.xz \
|
||||
&& tar xJf qemu-6.1.0.tar.xz > /dev/null \
|
||||
&& cd qemu-6.1.0 && ./configure --target-list=${{ matrix.arch }}-softmmu && cd ..
|
||||
cd qemu-6.1.0 && sudo make install -j
|
||||
cd qemu-${{ env.qemu_version }} && sudo make install
|
||||
qemu-system-${{ matrix.arch }} --version
|
||||
|
||||
- name: Prepare rootfs
|
||||
run: |
|
||||
if [ "${{ matrix.arch }}" = "x86_64" ]; then
|
||||
make baremetal-test-img
|
||||
elif [ "${{ matrix.arch }}" = "riscv64" ]; then
|
||||
make riscv-image
|
||||
fi
|
||||
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,15 +1,18 @@
|
|||
/target
|
||||
**/.*
|
||||
!.github/
|
||||
!.cargo/
|
||||
!.vscode/settings.json
|
||||
|
||||
**/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
/rootfs
|
||||
/riscv_rootfs
|
||||
/prebuilt/linux/alpine*
|
||||
/prebuilt/linux/riscv64/prebuild*
|
||||
zCore/src/platform/riscv/boot/kernel-vars.ld
|
||||
*.img
|
||||
*.bin
|
||||
*.log
|
||||
.idea
|
||||
Cargo.lock
|
||||
|
||||
/ignored
|
||||
/rootfs
|
||||
zCore/src/platform/riscv/kernel-vars.ld
|
||||
|
||||
.DS_Store
|
||||
.vscode/
|
||||
__pycache__
|
||||
|
|
|
|||
|
|
@ -4,3 +4,6 @@
|
|||
[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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
// Prevent "can't find crate for `test`" error on no_std
|
||||
// Ref: https://github.com/rust-lang/vscode-rust/issues/729
|
||||
// For vscode-rust plugin users:
|
||||
"rust.target": "riscv64imac-unknown-none-elf",
|
||||
"rust.all_targets": false,
|
||||
// For Rust Analyzer plugin users:
|
||||
"rust-analyzer.cargo.target": "riscv64imac-unknown-none-elf",
|
||||
"rust-analyzer.checkOnSave.enable": false
|
||||
}
|
||||
|
|
@ -8,12 +8,10 @@ members = [
|
|||
"linux-syscall",
|
||||
"loader",
|
||||
"zCore",
|
||||
"xtask",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
"zircon-user",
|
||||
"rboot",
|
||||
]
|
||||
default-members = ["xtask"]
|
||||
exclude = ["zircon-user", "rboot"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
|
|||
121
Makefile
121
Makefile
|
|
@ -1,100 +1,53 @@
|
|||
ROOTFS_TAR := alpine-minirootfs-3.12.0-x86_64.tar.gz
|
||||
ROOTFS_URL := http://dl-cdn.alpinelinux.org/alpine/v3.12/releases/x86_64/$(ROOTFS_TAR)
|
||||
|
||||
RISCV64_ROOTFS_TAR := prebuild.tar.xz
|
||||
RISCV64_ROOTFS_URL := https://github.com/rcore-os/libc-test-prebuilt/releases/download/0.1/$(RISCV64_ROOTFS_TAR)
|
||||
# Makefile for top level of zCore
|
||||
|
||||
ARCH ?= x86_64
|
||||
rcore_fs_fuse_revision := 7f5eeac
|
||||
OUT_IMG := zCore/$(ARCH).img
|
||||
TMP_ROOTFS := /tmp/rootfs
|
||||
|
||||
# for linux syscall tests
|
||||
TEST_DIR := linux-syscall/test/
|
||||
DEST_DIR := rootfs/bin/
|
||||
TEST_PATH := $(wildcard $(TEST_DIR)*.c)
|
||||
BASENAMES := $(notdir $(basename $(TEST_PATH)))
|
||||
.PHONY: help setup update rootfs libc-test other-test image check doc clean
|
||||
|
||||
CFLAG := -Wl,--dynamic-linker=/lib/ld-musl-x86_64.so.1
|
||||
# print top level help
|
||||
help:
|
||||
cargo xtask help
|
||||
|
||||
.PHONY: rootfs libc-test rcore-fs-fuse image
|
||||
# setup git lfs and git submodules
|
||||
setup:
|
||||
cargo setup
|
||||
|
||||
prebuilt/linux/$(ROOTFS_TAR):
|
||||
wget $(ROOTFS_URL) -O $@
|
||||
# update toolchain and dependencies
|
||||
update:
|
||||
cargo update-all
|
||||
|
||||
prebuilt/linux/riscv64/$(RISCV64_ROOTFS_TAR):
|
||||
@wget $(RISCV64_ROOTFS_URL) -O $@
|
||||
|
||||
rootfs: prebuilt/linux/$(ROOTFS_TAR)
|
||||
rm -rf rootfs && mkdir -p rootfs
|
||||
tar xf $< -C rootfs
|
||||
# libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore
|
||||
cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
|
||||
@for VAR in $(BASENAMES); do gcc $(TEST_DIR)$$VAR.c -o $(DEST_DIR)$$VAR $(CFLAG); done
|
||||
|
||||
riscv-rootfs:prebuilt/linux/riscv64/$(RISCV64_ROOTFS_TAR)
|
||||
@rm -rf riscv_rootfs && mkdir -p riscv_rootfs
|
||||
@tar -xvf $< -C riscv_rootfs --strip-components 1
|
||||
@ln -s busybox riscv_rootfs/bin/ls
|
||||
# put rootfs for linux mode
|
||||
rootfs:
|
||||
cargo rootfs --arch $(ARCH)
|
||||
|
||||
# put libc tests into rootfs
|
||||
libc-test:
|
||||
cd rootfs && git clone git://repo.or.cz/libc-test --depth 1
|
||||
cd rootfs/libc-test && cp config.mak.def config.mak && echo 'CC := musl-gcc' >> config.mak && make -j
|
||||
cargo libc-test --arch $(ARCH)
|
||||
|
||||
rcore-fs-fuse:
|
||||
ifneq ($(shell rcore-fs-fuse dir image git-version), $(rcore_fs_fuse_revision))
|
||||
@echo Installing rcore-fs-fuse
|
||||
@cargo install rcore-fs-fuse --git https://github.com/rcore-os/rcore-fs --rev $(rcore_fs_fuse_revision) --force
|
||||
endif
|
||||
# put other tests into rootfs
|
||||
other-test:
|
||||
cargo other-test --arch $(ARCH)
|
||||
|
||||
$(OUT_IMG): prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse
|
||||
@echo Generating $(ARCH).img
|
||||
@rm -rf $(TMP_ROOTFS)
|
||||
@mkdir -p $(TMP_ROOTFS)
|
||||
@tar xf $< -C $(TMP_ROOTFS)
|
||||
@cp $(TMP_ROOTFS)/lib/ld-musl-x86_64.so.1 rootfs/lib/
|
||||
@rcore-fs-fuse $@ rootfs zip
|
||||
# recover rootfs/ld-musl-x86_64.so.1 for zcore usr libos
|
||||
# libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore
|
||||
@cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
|
||||
# build image from rootfs
|
||||
image:
|
||||
cargo image --arch $(ARCH)
|
||||
|
||||
image: $(OUT_IMG)
|
||||
@echo Resizing $(ARCH).img
|
||||
@qemu-img resize $(OUT_IMG) +5M
|
||||
|
||||
|
||||
riscv-image: rcore-fs-fuse riscv-rootfs
|
||||
@echo building riscv.img
|
||||
@rcore-fs-fuse zCore/riscv64.img riscv_rootfs zip
|
||||
@qemu-img resize -f raw zCore/riscv64.img +5M
|
||||
|
||||
clean:
|
||||
cargo clean
|
||||
find zCore -maxdepth 1 -name "*.img" -delete
|
||||
rm -rf rootfs
|
||||
rm -rf riscv-rootfs
|
||||
find zCore/target -type f -name "*.zbi" -delete
|
||||
find zCore/target -type f -name "*.elf" -delete
|
||||
cd linux-syscall/test-oscomp && make clean
|
||||
cd linux-syscall/busybox && make clean
|
||||
cd linux-syscall/lua && make clean
|
||||
cd linux-syscall/lmbench && make clean
|
||||
# check code style
|
||||
check:
|
||||
cargo check-style
|
||||
|
||||
# build and open project document
|
||||
doc:
|
||||
cargo doc --open
|
||||
|
||||
baremetal-test-img: prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse
|
||||
@echo Generating $(ARCH).img
|
||||
@rm -rf $(TMP_ROOTFS)
|
||||
@mkdir -p $(TMP_ROOTFS)
|
||||
@tar xf $< -C $(TMP_ROOTFS)
|
||||
@mkdir -p rootfs/lib
|
||||
@cp $(TMP_ROOTFS)/lib/ld-musl-x86_64.so.1 rootfs/lib/
|
||||
@cd rootfs && rm -rf libc-test && git clone git://repo.or.cz/libc-test --depth 1
|
||||
@cd rootfs/libc-test && cp config.mak.def config.mak && echo 'CC := musl-gcc' >> config.mak && make -j
|
||||
@rcore-fs-fuse $(OUT_IMG) rootfs zip
|
||||
# recover rootfs/ld-musl-x86_64.so.1 for zcore usr libos
|
||||
# libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore
|
||||
@cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
|
||||
@echo Resizing $(ARCH).img
|
||||
@qemu-img resize $(OUT_IMG) +5M
|
||||
# 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.
|
||||
|
|
|
|||
47
README.md
47
README.md
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
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
|
||||
|
|
@ -24,9 +28,9 @@ make run ARCH=riscv64 LINUX=1
|
|||
|
||||
Environments:
|
||||
|
||||
* [Rust toolchain](http://rustup.rs)
|
||||
* [QEMU](https://www.qemu.org)
|
||||
* [Git LFS](https://git-lfs.github.com)
|
||||
- [Rust toolchain](http://rustup.rs)
|
||||
- [QEMU](https://www.qemu.org)
|
||||
- [Git LFS](https://git-lfs.github.com)
|
||||
|
||||
### Developing environment info
|
||||
|
||||
|
|
@ -48,15 +52,18 @@ For users in China, there's a mirror you can try:
|
|||
```sh
|
||||
git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
|
||||
```
|
||||
|
||||
### Run zcore in libos mode
|
||||
|
||||
#### Run zcore in linux-libos mode
|
||||
* step 1: Prepare Alpine Linux rootfs:
|
||||
|
||||
- step 1: Prepare Alpine Linux rootfs:
|
||||
|
||||
```sh
|
||||
make rootfs
|
||||
```
|
||||
|
||||
* step 2: Compile & Run native Linux program (Busybox) in libos mode:
|
||||
- step 2: Compile & Run native Linux program (Busybox) in libos mode:
|
||||
|
||||
```sh
|
||||
cargo run --release --features "linux libos" -- /bin/busybox [args]
|
||||
|
|
@ -68,7 +75,7 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
|
|||
|
||||
#### Run native Zircon program (shell) in zircon-libos mode:
|
||||
|
||||
* step 1: Compile and Run Zircon shell
|
||||
- step 1: Compile and Run Zircon shell
|
||||
|
||||
```sh
|
||||
cargo run --release --features "zircon libos" -- prebuilt/zircon/x64/bringup.zbi
|
||||
|
|
@ -77,15 +84,16 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
|
|||
The `graphic` and `LOG` options are the same as Linux.
|
||||
|
||||
### Run zcore in bare-metal mode
|
||||
|
||||
#### Run Linux shell in linux-bare-metal mode:
|
||||
|
||||
* step 1: Prepare Alpine Linux rootfs:
|
||||
- step 1: Prepare Alpine Linux rootfs:
|
||||
|
||||
```sh
|
||||
make rootfs
|
||||
```
|
||||
|
||||
* step 2: Create Linux rootfs image:
|
||||
- step 2: Create Linux rootfs image:
|
||||
|
||||
Note: Before below step, you can add some special apps in zCore/rootfs
|
||||
|
||||
|
|
@ -93,7 +101,7 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
|
|||
make image
|
||||
```
|
||||
|
||||
* step 3: Build and run zcore in linux-bare-metal mode:
|
||||
- step 3: Build and run zcore in linux-bare-metal mode:
|
||||
|
||||
```sh
|
||||
cd zCore && make run MODE=release LINUX=1 [LOG=warn] [GRAPHIC=on] [ACCEL=1]
|
||||
|
|
@ -101,13 +109,13 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
|
|||
|
||||
#### Run Zircon shell in zircon-bare-metal mode:
|
||||
|
||||
* step 1: Build and run zcore in zircon-bare-metal mode:
|
||||
- step 1: Build and run zcore in zircon-bare-metal mode:
|
||||
|
||||
```sh
|
||||
cd zCore && make run MODE=release [LOG=warn] [GRAPHIC=on] [ACCEL=1]
|
||||
```
|
||||
|
||||
* step 2: Build and run your own Zircon user programs:
|
||||
- step 2: Build and run your own Zircon user programs:
|
||||
|
||||
```sh
|
||||
# See template in zircon-user
|
||||
|
|
@ -118,6 +126,7 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
|
|||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### LibOS Mode Testing
|
||||
|
||||
#### Zircon related
|
||||
|
|
@ -148,6 +157,7 @@ cd scripts && python3 libos-libc-tests.py
|
|||
```
|
||||
|
||||
### Bare-metal Mode Testing
|
||||
|
||||
#### Zircon related
|
||||
|
||||
Run Zircon official core-tests on bare-metal:
|
||||
|
|
@ -167,6 +177,7 @@ cd scripts && python3 core-tests.py
|
|||
#### x86-64 Linux related
|
||||
|
||||
Run Linux musl libc-tests for CI:
|
||||
|
||||
```sh
|
||||
## Prepare rootfs with libc-test apps
|
||||
make baremetal-test-img
|
||||
|
|
@ -184,6 +195,7 @@ You can use [`scripts/baremetal-libc-test-ones.py`](./scripts/baremetal-libc-tes
|
|||
#### riscv-64 Linux related
|
||||
|
||||
Run Linux musl libc-tests for CI:
|
||||
|
||||
```sh
|
||||
## Prepare rootfs with libc-test & oscomp apps
|
||||
make riscv-image
|
||||
|
|
@ -192,25 +204,28 @@ cd scripts && python3 baremetal-test-riscv64.py
|
|||
##
|
||||
```
|
||||
|
||||
You can use[ `scripts/baremetal-libc-test-ones-riscv64.py`](./scripts/baremetal-libc-test-ones-riscv64.py) & [`scripts/linux/baremetal-test-ones-rv64.txt`](scripts/linux/baremetal-test-ones-rv64.txt)to test
|
||||
You can use[scripts/baremetal-libc-test-ones-riscv64.py](./scripts/baremetal-libc-test-ones-riscv64.py) & [`scripts/linux/baremetal-test-ones-rv64.txt`](scripts/linux/baremetal-test-ones-rv64.txt)to test
|
||||
specified apps.
|
||||
|
||||
[`scripts/linux/baremetal-test-fail-riscv64.txt`](./scripts/linux/baremetal-test-fail-riscv64.txt)includes all failed riscv-64 apps (We need YOUR HELP to fix bugs!)
|
||||
|
||||
## Graph/Game
|
||||
|
||||
snake game: https://github.com/rcore-os/rcore-user/blob/master/app/src/snake.c
|
||||
snake game: <https://github.com/rcore-os/rcore-user/blob/master/app/src/snake.c>
|
||||
|
||||
### Step1: compile usr app
|
||||
|
||||
We can use musl-gcc compile it in x86_64 mode
|
||||
|
||||
### Step2: change zcore for run snake app first.
|
||||
|
||||
change zCore/zCore/main.rs L176
|
||||
vec!["/bin/busybox".into(), "sh".into()]
|
||||
TO
|
||||
vec!["/bin/snake".into(), "sh".into()]
|
||||
|
||||
### Step3: prepare root fs image, run zcore in linux-bare-metal mode
|
||||
|
||||
exec:
|
||||
|
||||
```sh
|
||||
|
|
@ -235,12 +250,15 @@ Operation
|
|||
- `Middle`: Pause/Resume
|
||||
|
||||
## Doc
|
||||
|
||||
```
|
||||
make doc
|
||||
```
|
||||
|
||||
### RISC-V 64 porting info
|
||||
|
||||
- [porting riscv64 doc](./docs/porting-rv64.md)
|
||||
|
||||
## Components
|
||||
|
||||
### Overview
|
||||
|
|
@ -260,4 +278,5 @@ make doc
|
|||
| Exception Handling | Interrupt | Signal |
|
||||
|
||||
### Small Goal & Little Plans
|
||||
- https://github.com/rcore-os/zCore/wiki/Plans
|
||||
|
||||
- <https://github.com/rcore-os/zCore/wiki/Plans>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
# zCore 项目使用指南
|
||||
|
||||
## 预定功能
|
||||
|
||||
预定功能指的是 zCore 作为一个项目,为开发者和用户常用操作提供的封装。
|
||||
|
||||
由于历史原因,目前预定功能分为顶层预定功能和内核预定功能。
|
||||
所有顶层提供的预定功能都定义于 [顶层 Makefile](../Makefile),
|
||||
并且所有预定功能最终都将移动到顶层。
|
||||
|
||||
## 常规操作流程
|
||||
|
||||
对于一般开发者和用户,可以按以下步骤设置 zCore 项目。
|
||||
|
||||
1. 先决条件
|
||||
|
||||
目前已测试的开发环境包括 Ubuntu20.04、Ubuntu22.04 和 Debian11,
|
||||
Ubuntu22.04 不能正确编译 x86_64 的 libc 测试。
|
||||
若不需要烧写到物理硬件,使用 WSL2 或其他虚拟机的操作与真机并无不同之处。
|
||||
|
||||
在开始之前,确保你的计算机上安装了 git 和 rustup。要在虚拟环境开发或测试,需要 QEMU。
|
||||
|
||||
2. 克隆项目
|
||||
|
||||
```bash
|
||||
git clone https://github.com/rcore-os/zCore.git
|
||||
```
|
||||
|
||||
3. 初始化存储库
|
||||
|
||||
```bash
|
||||
make setup
|
||||
```
|
||||
|
||||
4. 保持更新
|
||||
|
||||
```bash
|
||||
make update
|
||||
```
|
||||
|
||||
5. 探索更多操作
|
||||
|
||||
```bash
|
||||
make help
|
||||
```
|
||||
|
||||
6. 推到仓库前,现在本机执行测试
|
||||
|
||||
```bash
|
||||
make check # CI/build 的一部分,未来会实现更多快速测试指令
|
||||
```
|
||||
|
||||
## Linux 模式
|
||||
|
||||
zCore 根据向用户提供的系统调用的不同,可分为 zircon 模式和 linux 模式。
|
||||
要以 linux 模式启动,需要先构建 linux 的启动文件系统。
|
||||
|
||||
这个指令构建适于 x86_64 架构的启动文件系统。
|
||||
|
||||
```bash
|
||||
make rootfs ARCH=x86_64
|
||||
```
|
||||
|
||||
这个指令构建适于 riscv64 架构的启动文件系统。
|
||||
|
||||
```bash
|
||||
make rootfs ARCH=riscv64
|
||||
```
|
||||
|
||||
要执行 musl-libc 测试集,需要向文件系统中添加 libc 测试集:
|
||||
|
||||
```bash
|
||||
make libc-test <ARCH=?>
|
||||
```
|
||||
|
||||
要执行 CI 的其他测试,需要向文件系统中添加相应测试集:
|
||||
|
||||
```bash
|
||||
make other-test <ARCH=?>
|
||||
```
|
||||
|
||||
要以裸机模式启动 zCore,需要构造将放到设备或虚拟环境中的镜像文件:
|
||||
|
||||
```bash
|
||||
make image <ARCH=?>
|
||||
```
|
||||
|
|
@ -20,19 +20,27 @@ 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 = "b3f9f51" }
|
||||
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 }
|
||||
# smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp"] }
|
||||
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
|
||||
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.0"
|
||||
acpi = "4.1"
|
||||
x2apic = "0.4"
|
||||
x86_64 = "0.14"
|
||||
|
||||
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
|
||||
riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }
|
||||
riscv = "0.8"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,18 @@
|
|||
// 解析设备树,创建已知的设备并为它们注册中断。
|
||||
//
|
||||
// 涉及到中断的设备包括:
|
||||
//
|
||||
// - 接收中断的中断控制器
|
||||
// - 发出中断的设备
|
||||
//
|
||||
// 有效的中断控制器应该具有下列三个属性:
|
||||
//
|
||||
// - `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>.
|
||||
|
|
@ -5,24 +20,27 @@
|
|||
use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
|
||||
|
||||
use super::IoMapper;
|
||||
use crate::utils::devicetree::{parse_interrupts, parse_reg};
|
||||
use crate::utils::devicetree::{Devicetree, InheritProps, InterruptsProp, Node, StringList};
|
||||
use crate::{Device, DeviceError, DeviceResult, VirtAddr};
|
||||
use crate::{
|
||||
utils::devicetree::{
|
||||
parse_interrupts, parse_reg, Devicetree, InheritProps, InterruptsProp, Node, StringList,
|
||||
},
|
||||
Device, DeviceError, DeviceResult, VirtAddr,
|
||||
};
|
||||
|
||||
/// A wrapper of [`Device`] which provides interrupt information additionally.
|
||||
#[derive(Debug)]
|
||||
struct DevWithInterrupt {
|
||||
/// For interrupt controller, represent the `phandle` property, otherwise
|
||||
/// is `None`.
|
||||
phandle: Option<u32>,
|
||||
/// For interrupt controller, represent the `interrupt_cells` property,
|
||||
/// otherwise is `None`.
|
||||
interrupt_cells: Option<u32>,
|
||||
/// A unified representation of the `interrupts` and `interrupts_extended`
|
||||
/// properties for any interrupt generating device.
|
||||
interrupts_extended: InterruptsProp,
|
||||
/// The inner [`Device`] structure.
|
||||
dev: Device,
|
||||
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.
|
||||
|
|
@ -42,26 +60,78 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
|
|||
|
||||
/// Parse the device tree from root, and returns an array of [`Device`] it found.
|
||||
pub fn build(&self) -> DeviceResult<Vec<Device>> {
|
||||
let mut intc_map = BTreeMap::new();
|
||||
let mut dev_list = Vec::new();
|
||||
let mut intc_map = BTreeMap::new(); // phandle -> intc
|
||||
let mut dev_list = Vec::new(); // devices
|
||||
|
||||
// 解析设备树
|
||||
self.dt.walk(&mut |node, comp, props| {
|
||||
if let Ok(dev) = self.parse_device(node, comp, props) {
|
||||
// create the phandle-device mapping
|
||||
if node.has_prop("interrupt-controller") {
|
||||
if let Some(phandle) = dev.phandle {
|
||||
intc_map.insert(phandle, dev_list.len());
|
||||
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),
|
||||
}
|
||||
dev_list.push(dev);
|
||||
};
|
||||
match res {
|
||||
Ok(dev) => dev_list.push(dev),
|
||||
Err(DeviceError::NotSupported) => {}
|
||||
Err(err) => warn!("{MODULE}: failed to parsing node {:?}: {err:?}", node.name),
|
||||
}
|
||||
});
|
||||
|
||||
for dev in &dev_list {
|
||||
register_interrupt(dev, &dev_list, &intc_map).ok();
|
||||
// 注册中断
|
||||
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(|d| d.dev).collect())
|
||||
// 丢弃中断信息
|
||||
Ok(dev_list.into_iter().map(|(dev, _)| dev).collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,56 +140,20 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
|
|||
#[allow(unused_variables)]
|
||||
#[allow(unreachable_code)]
|
||||
impl<M: IoMapper> DevicetreeDriverBuilder<M> {
|
||||
/// Parse device nodes
|
||||
fn parse_device(
|
||||
&self,
|
||||
node: &Node,
|
||||
comp: &StringList,
|
||||
props: &InheritProps,
|
||||
) -> DeviceResult<DevWithInterrupt> {
|
||||
debug!(
|
||||
"device-tree: parsing node {:?} with compatible {:?}",
|
||||
node.name, comp
|
||||
);
|
||||
// parse interrupt controller
|
||||
let res = if node.has_prop("interrupt-controller") {
|
||||
self.parse_intc(node, comp, props)
|
||||
} else {
|
||||
// parse other device
|
||||
match comp {
|
||||
#[cfg(feature = "virtio")]
|
||||
c if c.contains("virtio,mmio") => self.parse_virtio(node, props),
|
||||
c if c.contains("allwinner,sunxi-gmac") => self.parse_ethernet(node, comp, props),
|
||||
c if c.contains("ns16550a") => self.parse_uart(node, comp, props),
|
||||
c if c.contains("allwinner,sun20i-uart") => self.parse_uart(node, comp, props),
|
||||
_ => Err(DeviceError::NotSupported),
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = &res {
|
||||
if !matches!(err, DeviceError::NotSupported) {
|
||||
warn!(
|
||||
"device-tree: failed to parsing node {:?}: {:?}",
|
||||
node.name, err
|
||||
);
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
/// Parse nodes for interrupt controllers.
|
||||
fn parse_intc(
|
||||
&self,
|
||||
node: &Node,
|
||||
comp: &StringList,
|
||||
props: &InheritProps,
|
||||
) -> DeviceResult<DevWithInterrupt> {
|
||||
let phandle = node.prop_u32("phandle").ok();
|
||||
let interrupt_cells = node.prop_u32("#interrupt-cells").ok();
|
||||
) -> 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)?;
|
||||
if phandle.is_none() || interrupt_cells.is_none() {
|
||||
return Err(DeviceError::InvalidParam);
|
||||
}
|
||||
let base_vaddr = parse_reg(node, props).and_then(|(paddr, size)| {
|
||||
self.io_mapper
|
||||
.query_or_map(paddr as usize, size as usize)
|
||||
|
|
@ -134,12 +168,13 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
|
|||
_ => return Err(DeviceError::NotSupported),
|
||||
});
|
||||
|
||||
Ok(DevWithInterrupt {
|
||||
phandle,
|
||||
interrupt_cells,
|
||||
interrupts_extended,
|
||||
dev,
|
||||
})
|
||||
Ok((
|
||||
(dev, interrupts_extended),
|
||||
IntcProps {
|
||||
phandle,
|
||||
interrupt_cells,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
/// Parse nodes for virtio devices over MMIO.
|
||||
|
|
@ -159,7 +194,7 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
|
|||
return Err(DeviceError::NotSupported);
|
||||
}
|
||||
info!(
|
||||
"device-tree: detected virtio device: vendor_id={:#X}, type={:?}",
|
||||
"{MODULE}: detected virtio device: vendor_id={:#X}, type={:?}",
|
||||
header.vendor_id(),
|
||||
header.device_type()
|
||||
);
|
||||
|
|
@ -172,12 +207,7 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
|
|||
_ => return Err(DeviceError::NotSupported),
|
||||
};
|
||||
|
||||
Ok(DevWithInterrupt {
|
||||
phandle: None,
|
||||
interrupt_cells: None,
|
||||
interrupts_extended,
|
||||
dev,
|
||||
})
|
||||
Ok((dev, interrupts_extended))
|
||||
}
|
||||
|
||||
/// Parse nodes for Ethernet devices.
|
||||
|
|
@ -207,12 +237,7 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
|
|||
_ => return Err(DeviceError::NotSupported),
|
||||
});
|
||||
|
||||
Ok(DevWithInterrupt {
|
||||
phandle: None,
|
||||
interrupt_cells: None,
|
||||
interrupts_extended,
|
||||
dev,
|
||||
})
|
||||
Ok((dev, interrupts_extended))
|
||||
}
|
||||
|
||||
/// Parse nodes for UART devices.
|
||||
|
|
@ -240,57 +265,6 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
|
|||
_ => return Err(DeviceError::NotSupported),
|
||||
});
|
||||
|
||||
Ok(DevWithInterrupt {
|
||||
phandle: None,
|
||||
interrupt_cells: None,
|
||||
interrupts_extended,
|
||||
dev,
|
||||
})
|
||||
Ok((dev, interrupts_extended))
|
||||
}
|
||||
}
|
||||
|
||||
/// Register interrupts for `dev` according to its interrupt parent, which can
|
||||
/// be found from the phandle-device mapping.
|
||||
fn register_interrupt(
|
||||
dev: &DevWithInterrupt,
|
||||
dev_list: &[DevWithInterrupt],
|
||||
intc_map: &BTreeMap<u32, usize>,
|
||||
) -> DeviceResult {
|
||||
let mut pos = 0;
|
||||
while pos < dev.interrupts_extended.len() {
|
||||
let parent = dev.interrupts_extended[pos];
|
||||
// find the interrupt parent in `dev_list`
|
||||
if let Some(intc) = intc_map.get(&parent).map(|&i| &dev_list[i]) {
|
||||
let cells = intc.interrupt_cells.ok_or(DeviceError::InvalidParam)?;
|
||||
if let Device::Irq(irq) = &intc.dev {
|
||||
// get irq_num from the `interrupts_extended` property
|
||||
let irq_num = dev.interrupts_extended[pos + 1] as usize;
|
||||
if irq_num != 0xffff_ffff {
|
||||
info!(
|
||||
"device-tree: register interrupts for {:?}: {:?}, irq_num={}",
|
||||
intc.dev, dev.dev, irq_num
|
||||
);
|
||||
|
||||
irq.register_device(irq_num, dev.dev.inner())?;
|
||||
// enable the interrupt after registration
|
||||
irq.unmask(irq_num)?;
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"device-tree: node with phandle {:#x} is not an interrupt-controller",
|
||||
parent
|
||||
);
|
||||
return Err(DeviceError::InvalidParam);
|
||||
}
|
||||
// process the next interrupt parent
|
||||
pos += 1 + cells as usize;
|
||||
} else {
|
||||
warn!(
|
||||
"device-tree: no such node with phandle {:#x} as the interrupt-parent",
|
||||
parent
|
||||
);
|
||||
return Err(DeviceError::InvalidParam);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
#![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) }
|
||||
}
|
||||
|
|
@ -0,0 +1,327 @@
|
|||
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,3 +1,5 @@
|
|||
//! Only UEFI Display currently.
|
||||
|
||||
mod uefi;
|
||||
|
||||
pub use uefi::UefiDisplay;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Only Mouse currently.
|
||||
|
||||
mod mouse;
|
||||
|
||||
pub mod input_event_codes;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use alloc::{boxed::Box, sync::Arc};
|
||||
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::prelude::{CapabilityType, InputEvent, InputEventType};
|
||||
use crate::scheme::{impl_event_scheme, InputScheme};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
use core::mem::MaybeUninit;
|
||||
use super::Io;
|
||||
use core::ops::{BitAnd, BitOr, Not};
|
||||
|
||||
use super::Io;
|
||||
|
||||
// 主存映射 I/O。
|
||||
/// Memory-mapped I/O.
|
||||
#[repr(transparent)]
|
||||
pub struct Mmio<T> {
|
||||
value: MaybeUninit<T>,
|
||||
}
|
||||
pub struct Mmio<T>(T);
|
||||
|
||||
impl<T> Mmio<T> {
|
||||
/// # Safety
|
||||
|
|
@ -25,9 +23,7 @@ impl<T> Mmio<T> {
|
|||
}
|
||||
|
||||
pub fn add<'a>(&self, offset: usize) -> &'a mut Self {
|
||||
unsafe {
|
||||
Self::from_base(self.value.as_ptr() as usize + offset * core::mem::size_of::<T>())
|
||||
}
|
||||
unsafe { Self::from_base((&self.0 as *const T).add(offset) as _) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -38,10 +34,20 @@ where
|
|||
type Value = T;
|
||||
|
||||
fn read(&self) -> T {
|
||||
unsafe { core::ptr::read_volatile(self.value.as_ptr()) }
|
||||
#[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 { core::ptr::write_volatile(self.value.as_mut_ptr(), value) };
|
||||
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,55 +1,79 @@
|
|||
// 封装对外设地址空间的访问,包括内存映射 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 pio;
|
||||
mod pmio;
|
||||
|
||||
pub use mmio::Mmio;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use pio::Pio;
|
||||
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> {
|
||||
inner: I,
|
||||
}
|
||||
pub struct ReadOnly<I>(I);
|
||||
|
||||
impl<I> ReadOnly<I> {
|
||||
pub const fn new(inner: I) -> ReadOnly<I> {
|
||||
ReadOnly { inner }
|
||||
// 构造外设地址空间的一个只读单元。
|
||||
/// 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.inner.read()
|
||||
self.0.read()
|
||||
}
|
||||
}
|
||||
|
||||
// 外设地址空间的一个只写单元。
|
||||
/// A write-only unit in device address space.
|
||||
#[repr(transparent)]
|
||||
pub struct WriteOnly<I> {
|
||||
inner: I,
|
||||
}
|
||||
pub struct WriteOnly<I>(I);
|
||||
|
||||
impl<I> WriteOnly<I> {
|
||||
pub const fn new(inner: I) -> WriteOnly<I> {
|
||||
WriteOnly { inner }
|
||||
// 构造外设地址空间的一个只写单元。
|
||||
/// 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.inner.write(value)
|
||||
self.0.write(value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,35 @@
|
|||
use core::arch::asm;
|
||||
use core::marker::PhantomData;
|
||||
// 端口映射 I/O。
|
||||
//! Port-mapped I/O.
|
||||
|
||||
use super::Io;
|
||||
use core::{arch::asm, marker::PhantomData};
|
||||
|
||||
/// Generic PIO
|
||||
// 端口映射 I/O。
|
||||
/// Port-mapped I/O.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Pio<T> {
|
||||
pub struct Pmio<T> {
|
||||
port: u16,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Pio<T> {
|
||||
/// Create a PIO from a given port
|
||||
impl<T> Pmio<T> {
|
||||
// 映射指定端口进行外设访问。
|
||||
/// Maps a given port to assess device.
|
||||
pub const fn new(port: u16) -> Self {
|
||||
Pio::<T> {
|
||||
Self {
|
||||
port,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read/Write for byte PIO
|
||||
impl Io for Pio<u8> {
|
||||
// 逐字节端口映射读写。
|
||||
/// Read/Write for byte PMIO.
|
||||
impl Io for Pmio<u8> {
|
||||
type Value = u8;
|
||||
|
||||
/// Read
|
||||
// 读。
|
||||
/// Read.
|
||||
#[inline(always)]
|
||||
fn read(&self) -> u8 {
|
||||
let value: u8;
|
||||
|
|
@ -34,7 +39,8 @@ impl Io for Pio<u8> {
|
|||
value
|
||||
}
|
||||
|
||||
/// Write
|
||||
// 写。
|
||||
/// Write.
|
||||
#[inline(always)]
|
||||
fn write(&mut self, value: u8) {
|
||||
unsafe {
|
||||
|
|
@ -43,11 +49,13 @@ impl Io for Pio<u8> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Read/Write for word PIO
|
||||
impl Io for Pio<u16> {
|
||||
// 逐字端口映射读写。
|
||||
/// Read/Write for word PMIO.
|
||||
impl Io for Pmio<u16> {
|
||||
type Value = u16;
|
||||
|
||||
/// Read
|
||||
// 读。
|
||||
/// Read.
|
||||
#[inline(always)]
|
||||
fn read(&self) -> u16 {
|
||||
let value: u16;
|
||||
|
|
@ -57,7 +65,8 @@ impl Io for Pio<u16> {
|
|||
value
|
||||
}
|
||||
|
||||
/// Write
|
||||
// 写。
|
||||
/// Write.
|
||||
#[inline(always)]
|
||||
fn write(&mut self, value: u16) {
|
||||
unsafe {
|
||||
|
|
@ -66,11 +75,13 @@ impl Io for Pio<u16> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Read/Write for doubleword PIO
|
||||
impl Io for Pio<u32> {
|
||||
// 逐双字端口映射读写。
|
||||
/// Read/Write for double-word PMIO.
|
||||
impl Io for Pmio<u32> {
|
||||
type Value = u32;
|
||||
|
||||
/// Read
|
||||
// 读。
|
||||
/// Read.
|
||||
#[inline(always)]
|
||||
fn read(&self) -> u32 {
|
||||
let value: u32;
|
||||
|
|
@ -80,7 +91,8 @@ impl Io for Pio<u32> {
|
|||
value
|
||||
}
|
||||
|
||||
/// Write
|
||||
// 写。
|
||||
/// Write.
|
||||
#[inline(always)]
|
||||
fn write(&mut self, value: u32) {
|
||||
unsafe {
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
//! 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};
|
||||
|
|
@ -10,7 +13,7 @@ cfg_if::cfg_if! {
|
|||
}
|
||||
} else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
|
||||
mod x86_apic;
|
||||
|
||||
/// Implementation of x86 Advanced Programmable Interrupt Controller.
|
||||
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
pub mod x86 {
|
||||
pub use super::x86_apic::Apic;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use lock::Mutex;
|
||||
use riscv::register::sie;
|
||||
use spin::Mutex;
|
||||
|
||||
use crate::prelude::IrqHandler;
|
||||
use crate::scheme::{IrqScheme, Scheme};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use core::arch::asm;
|
||||
use core::ops::Range;
|
||||
use spin::Mutex;
|
||||
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::io::{Io, Mmio};
|
||||
use crate::prelude::IrqHandler;
|
||||
|
|
@ -38,8 +39,7 @@ impl PlicUnlocked {
|
|||
let hart_id = cpu_id() as usize;
|
||||
let mmio = self
|
||||
.enable_base
|
||||
.add(PLIC_ENABLE_HART_OFFSET * hart_id)
|
||||
.add(irq_num / 32);
|
||||
.add(PLIC_ENABLE_HART_OFFSET * hart_id + irq_num / 32);
|
||||
|
||||
let mask = 1 << (irq_num % 32);
|
||||
if enable {
|
||||
|
|
@ -54,8 +54,7 @@ impl PlicUnlocked {
|
|||
let hart_id = cpu_id() as usize;
|
||||
let irq_num = self
|
||||
.context_base
|
||||
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
|
||||
.add(PLIC_CONTEXT_CLAIM)
|
||||
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id + PLIC_CONTEXT_CLAIM)
|
||||
.read() as usize;
|
||||
if irq_num == 0 {
|
||||
None
|
||||
|
|
@ -69,8 +68,7 @@ impl PlicUnlocked {
|
|||
debug_assert!(IRQ_RANGE.contains(&irq_num));
|
||||
let hart_id = cpu_id() as usize;
|
||||
self.context_base
|
||||
.add(PLIC_CONTEXT_CLAIM)
|
||||
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
|
||||
.add(PLIC_CONTEXT_CLAIM + PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
|
||||
.write(irq_num as _);
|
||||
}
|
||||
|
||||
|
|
@ -84,8 +82,7 @@ impl PlicUnlocked {
|
|||
fn set_threshold(&mut self, threshold: u8) {
|
||||
let hart_id = cpu_id() as usize;
|
||||
self.context_base
|
||||
.add(PLIC_PRIORITY_HART_OFFSET * hart_id)
|
||||
.add(PLIC_CONTEXT_THRESHOLD)
|
||||
.add(PLIC_PRIORITY_HART_OFFSET * hart_id + PLIC_CONTEXT_THRESHOLD)
|
||||
.write(threshold as _);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use core::{fmt, ptr::NonNull};
|
|||
|
||||
use acpi::platform::interrupt::InterruptModel;
|
||||
use acpi::{AcpiHandler, AcpiTables, PhysicalMapping};
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
use x2apic::ioapic::{IoApic as IoApicInner, IrqFlags, IrqMode};
|
||||
|
||||
use super::{IrqPolarity, IrqTriggerMode, Phys2VirtFn};
|
||||
|
|
@ -66,9 +66,23 @@ impl IoApic {
|
|||
let mut inner = unsafe { IoApicInner::new(base_vaddr as u64) };
|
||||
let max_entry = unsafe { inner.max_table_entry() };
|
||||
unsafe { assert_eq!(id, inner.id()) };
|
||||
// disable all interrupts
|
||||
|
||||
unsafe {
|
||||
inner.init(super::X86_INT_BASE as u8);
|
||||
}
|
||||
for i in 0..max_entry + 1 {
|
||||
unsafe { inner.disable_irq(i) }
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use x2apic::lapic::{xapic_base, LocalApic as LocalApicInner, LocalApicBuilder};
|
||||
use x2apic::lapic::{
|
||||
xapic_base, LocalApic as LocalApicInner, LocalApicBuilder, TimerDivide, TimerMode,
|
||||
};
|
||||
|
||||
use super::{consts, Phys2VirtFn};
|
||||
|
||||
|
|
@ -47,4 +49,24 @@ impl LocalApic {
|
|||
pub fn eoi(&mut self) {
|
||||
unsafe { self.inner.end_of_interrupt() }
|
||||
}
|
||||
|
||||
pub fn disable_timer(&mut self) {
|
||||
unsafe { self.inner.disable_timer() }
|
||||
}
|
||||
|
||||
pub fn enable_timer(&mut self) {
|
||||
unsafe { self.inner.enable_timer() }
|
||||
}
|
||||
|
||||
pub fn set_timer_mode(&mut self, mode: TimerMode) {
|
||||
unsafe { self.inner.set_timer_mode(mode) }
|
||||
}
|
||||
|
||||
pub fn set_timer_divide(&mut self, divide: TimerDivide) {
|
||||
unsafe { self.inner.set_timer_divide(divide) }
|
||||
}
|
||||
|
||||
pub fn set_timer_initial(&mut self, initial: u32) {
|
||||
unsafe { self.inner.set_timer_initial(initial) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,22 +2,21 @@ mod consts;
|
|||
mod ioapic;
|
||||
mod lapic;
|
||||
|
||||
use core::ops::Range;
|
||||
|
||||
use spin::Mutex;
|
||||
|
||||
use self::consts::{X86_INT_BASE, X86_INT_LOCAL_APIC_BASE};
|
||||
use self::ioapic::{IoApic, IoApicList};
|
||||
use self::lapic::LocalApic;
|
||||
use crate::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
|
||||
use crate::scheme::{IrqScheme, Scheme};
|
||||
use crate::{utils::IrqManager, DeviceError, DeviceResult, PhysAddr, VirtAddr};
|
||||
use core::ops::Range;
|
||||
use lock::Mutex;
|
||||
|
||||
const IOAPIC_IRQ_RANGE: Range<usize> = X86_INT_BASE..X86_INT_LOCAL_APIC_BASE;
|
||||
const LAPIC_IRQ_RANGE: Range<usize> = 0..16;
|
||||
|
||||
type Phys2VirtFn = fn(paddr: PhysAddr) -> VirtAddr;
|
||||
|
||||
/// Advanced Programmable Interrupt Controller
|
||||
pub struct Apic {
|
||||
ioapic_list: IoApicList,
|
||||
manager_ioapic: Mutex<IrqManager<256>>,
|
||||
|
|
@ -25,6 +24,7 @@ pub struct Apic {
|
|||
}
|
||||
|
||||
impl Apic {
|
||||
/// Construct a new `Apic`.
|
||||
pub fn new(acpi_rsdp: usize, phys_to_virt: Phys2VirtFn) -> Self {
|
||||
Self {
|
||||
ioapic_list: IoApicList::new(acpi_rsdp, phys_to_virt),
|
||||
|
|
@ -81,9 +81,8 @@ impl Scheme for Apic {
|
|||
fn handle_irq(&self, vector: usize) {
|
||||
Self::local_apic().eoi();
|
||||
let res = if vector >= X86_INT_LOCAL_APIC_BASE {
|
||||
self.manager_lapic
|
||||
.lock()
|
||||
.handle(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)
|
||||
};
|
||||
|
|
@ -169,4 +168,9 @@ impl IrqScheme for Apic {
|
|||
Err(DeviceError::InvalidParam)
|
||||
}
|
||||
}
|
||||
|
||||
fn apic_timer_enable(&self) {
|
||||
// SAFETY: this will called only once for every core
|
||||
Apic::local_apic().enable_timer();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Device drivers of zCore.
|
||||
|
||||
#![cfg_attr(not(feature = "mock"), no_std)]
|
||||
#![feature(doc_cfg)]
|
||||
|
||||
|
|
@ -18,6 +20,7 @@ pub mod mock;
|
|||
pub mod virtio;
|
||||
|
||||
pub mod builder;
|
||||
pub mod bus;
|
||||
pub mod display;
|
||||
pub mod input;
|
||||
pub mod io;
|
||||
|
|
@ -28,6 +31,7 @@ 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.
|
||||
|
|
@ -48,19 +52,28 @@ pub enum DeviceError {
|
|||
NotSupported,
|
||||
}
|
||||
|
||||
/// A type alias for the result of a device operation.
|
||||
pub type DeviceResult<T = ()> = core::result::Result<T, DeviceError>;
|
||||
|
||||
/// Static shell of shared dynamic device [`Scheme`](crate::scheme::Scheme) types.
|
||||
#[derive(Clone)]
|
||||
pub enum Device {
|
||||
/// Block device
|
||||
Block(Arc<dyn scheme::BlockScheme>),
|
||||
/// Display device
|
||||
Display(Arc<dyn scheme::DisplayScheme>),
|
||||
/// Input device
|
||||
Input(Arc<dyn scheme::InputScheme>),
|
||||
/// Interrupt request and handle
|
||||
Irq(Arc<dyn scheme::IrqScheme>),
|
||||
/// Network device
|
||||
Net(Arc<dyn scheme::NetScheme>),
|
||||
/// Uart port
|
||||
Uart(Arc<dyn scheme::UartScheme>),
|
||||
}
|
||||
|
||||
impl Device {
|
||||
/// Get a general [`Scheme`](scheme::Scheme) from the device.
|
||||
pub fn inner(&self) -> Arc<dyn scheme::Scheme> {
|
||||
match self {
|
||||
Self::Block(d) => d.clone().upcast(),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Mock devices, including display, input, uart and graphic.
|
||||
|
||||
pub mod display;
|
||||
pub mod input;
|
||||
pub mod uart;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use async_std::{io, io::prelude::*, task};
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
|
||||
use crate::utils::EventListener;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,218 @@
|
|||
//! 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)
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ use crate::net::get_sockets;
|
|||
use alloc::sync::Arc;
|
||||
|
||||
use alloc::string::String;
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::scheme::{NetScheme, Scheme};
|
||||
use crate::{DeviceError, DeviceResult};
|
||||
|
|
@ -54,7 +54,7 @@ impl NetScheme for LoopbackInterface {
|
|||
fn get_ifname(&self) -> String {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_ip_addrrs(&self) -> Vec<IpCidr> {
|
||||
fn get_ip_address(&self) -> Vec<IpCidr> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
//! LAN driver, only for Realtek currently.
|
||||
|
||||
pub mod e1000;
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "riscv64")] {
|
||||
mod realtek;
|
||||
|
|
@ -7,6 +10,7 @@ pub use rtlx::*;
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// External functions that drivers must use
|
||||
pub trait Provider {
|
||||
/// Page size (usually 4K)
|
||||
|
|
@ -20,6 +24,8 @@ pub trait Provider {
|
|||
/// Deallocate DMA
|
||||
fn dealloc_dma(vaddr: usize, size: usize);
|
||||
}
|
||||
*/
|
||||
pub use isomorphic_drivers::provider::Provider;
|
||||
|
||||
pub struct ProviderImpl;
|
||||
|
||||
|
|
@ -63,7 +69,7 @@ pub use loopback::LoopbackInterface;
|
|||
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec;
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
|
||||
use smoltcp::socket::SocketSet;
|
||||
|
||||
|
|
|
|||
|
|
@ -214,7 +214,6 @@ impl<P> RTL8211F<P>
|
|||
where
|
||||
P: Provider,
|
||||
{
|
||||
#[allow(clippy::clone_on_copy)]
|
||||
pub fn new(mac_addr: &[u8; 6]) -> Self {
|
||||
assert_eq!(size_of::<dma_desc>(), 16);
|
||||
|
||||
|
|
@ -235,7 +234,7 @@ where
|
|||
mac[i] = u8::from_str_radix(s, 16).unwrap();
|
||||
}
|
||||
} else {
|
||||
mac = mac_addr.clone();
|
||||
mac = *mac_addr;
|
||||
}
|
||||
|
||||
info!(
|
||||
|
|
@ -1142,12 +1141,10 @@ where
|
|||
status = tx_dma_irq_status::tx_hard_error as i32;
|
||||
}
|
||||
|
||||
#[allow(clippy::collapsible_if)]
|
||||
/* 正常的 TX/RX NORMAL interrupts */
|
||||
if (intr_status & (TX_INT | RX_INT | RX_EARLY_INT | TX_UA_INT)) != 0 {
|
||||
if (intr_status & (TX_INT | RX_INT)) != 0 {
|
||||
status = tx_dma_irq_status::handle_tx_rx as i32;
|
||||
}
|
||||
// (intr_status & (TX_INT | RX_INT | RX_EARLY_INT | TX_UA_INT)) != 0
|
||||
if (intr_status & (TX_INT | RX_INT)) != 0 {
|
||||
status = tx_dma_irq_status::handle_tx_rx as i32;
|
||||
}
|
||||
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
|
||||
write_volatile((self.base + GETH_INT_STA) as *mut u32, intr_status & 0x3FFF);
|
||||
|
|
@ -1434,7 +1431,6 @@ where
|
|||
|
||||
match speed {
|
||||
1000 => ctrl &= !0x0C,
|
||||
/*100 | 10 |*/
|
||||
_ => {
|
||||
ctrl |= 0x08;
|
||||
if (speed == 100) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// c906
|
||||
use core::arch::asm;
|
||||
|
||||
// c906
|
||||
const FREQUENCY: u64 = 24_000_000; // C906: 24_000_000, Qemu: 10_000_000
|
||||
const MMIO_MTIMECMP0: *mut u64 = 0x0200_4000usize as *mut u64;
|
||||
const MMIO_MTIME: *const u64 = 0x0200_BFF8 as *const u64;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use alloc::collections::BTreeMap;
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec;
|
||||
// use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
|
||||
use smoltcp::iface::*;
|
||||
use smoltcp::phy::{self, Device, DeviceCapabilities, Medium};
|
||||
use smoltcp::socket::SocketSet;
|
||||
// use smoltcp::socket::SocketSet;
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::*;
|
||||
use smoltcp::Result;
|
||||
|
|
@ -18,6 +18,7 @@ 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};
|
||||
|
||||
|
|
@ -48,13 +49,13 @@ impl Scheme for RTLxInterface {
|
|||
let handle_tx_rx = 3;
|
||||
if status == handle_tx_rx {
|
||||
let timestamp = Instant::from_millis(0);
|
||||
let mut sockets = SOCKETS.lock(); //引发死锁?
|
||||
let sockets = get_sockets();
|
||||
let mut sockets = sockets.lock();
|
||||
|
||||
self.driver.0.lock().int_disable();
|
||||
match self.iface.lock().poll(&mut sockets, timestamp) {
|
||||
Ok(_) => {
|
||||
//SOCKET_ACTIVITY.notify_all();
|
||||
debug!("try_handle_interrupt SOCKET_ACTIVITY unimplemented");
|
||||
Ok(b) => {
|
||||
debug!("nic poll, is changed ?: {}", b);
|
||||
}
|
||||
Err(err) => {
|
||||
error!("poll got err {}", err);
|
||||
|
|
@ -75,17 +76,17 @@ impl NetScheme for RTLxInterface {
|
|||
self.name.clone()
|
||||
}
|
||||
|
||||
fn get_ip_addrrs(&self) -> Vec<IpCidr> {
|
||||
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 mut sockets = SOCKETS.lock();
|
||||
let sockets = get_sockets();
|
||||
let mut sockets = sockets.lock();
|
||||
match self.iface.lock().poll(&mut sockets, timestamp) {
|
||||
Ok(_) => {
|
||||
//SOCKET_ACTIVITY.notify_all();
|
||||
error!("poll, SOCKET_ACTIVITY unimplemented");
|
||||
Ok(b) => {
|
||||
debug!("nic poll, is changed ?: {}", b);
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
|
|
@ -192,14 +193,20 @@ pub fn rtlx_init<F: Fn(usize, usize) -> Option<usize>>(
|
|||
|
||||
let ethernet_addr = EthernetAddress::from_bytes(&mac);
|
||||
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 0, 123), 24)];
|
||||
let default_gateway = Ipv4Address::new(192, 168, 0, 1);
|
||||
static mut ROUTES_STORAGE: [Option<(IpCidr, Route)>; 1] = [None; 1];
|
||||
let mut routes = unsafe { Routes::new(&mut ROUTES_STORAGE[..]) };
|
||||
routes.add_default_ipv4_route(default_gateway).unwrap();
|
||||
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||
let iface = InterfaceBuilder::new(net_driver.clone())
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.ip_addrs(ip_addrs)
|
||||
.routes(routes)
|
||||
.finalize();
|
||||
|
||||
info!("rtl8211f interface up with addr 192.168.0.123/24");
|
||||
info!("rtl8211f interface up with route 192.168.0.1/24");
|
||||
let rtl8211f_iface = RTLxInterface {
|
||||
iface: Arc::new(Mutex::new(iface)),
|
||||
driver: net_driver,
|
||||
|
|
@ -211,7 +218,7 @@ pub fn rtlx_init<F: Fn(usize, usize) -> Option<usize>>(
|
|||
}
|
||||
|
||||
//TODO: Global SocketSet
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref SOCKETS: Mutex<SocketSet<'static>> =
|
||||
Mutex::new(SocketSet::new(vec![]));
|
||||
}
|
||||
// lazy_static::lazy_static! {
|
||||
// pub static ref SOCKETS: Mutex<SocketSet<'static>> =
|
||||
// Mutex::new(SocketSet::new(vec![]));
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
//! 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};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use core::ops::Range;
|
|||
use super::Scheme;
|
||||
use crate::DeviceResult;
|
||||
|
||||
/// A type alias for
|
||||
pub type IrqHandler = Box<dyn Fn() + Send + Sync>;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -75,4 +76,9 @@ pub trait IrqScheme: Scheme {
|
|||
fn init_hart(&self) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// [for x86_64] enable apic timer
|
||||
fn apic_timer_enable(&self) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//! The [`Scheme`] describe some functions must be implemented for device, there are
|
||||
//! many [`Scheme`] traits in this mod.
|
||||
//! 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.
|
||||
//!
|
||||
|
|
@ -26,12 +26,20 @@ 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;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ pub trait NetScheme: Scheme {
|
|||
fn send(&self, buf: &[u8]) -> DeviceResult<usize>;
|
||||
fn get_mac(&self) -> EthernetAddress;
|
||||
fn get_ifname(&self) -> String;
|
||||
fn get_ip_addrrs(&self) -> Vec<IpCidr>;
|
||||
fn get_ip_address(&self) -> Vec<IpCidr>;
|
||||
fn poll(&self) -> DeviceResult;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use alloc::{boxed::Box, collections::VecDeque, string::String, sync::Arc};
|
||||
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
|
||||
use crate::utils::EventListener;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Uart device driver.
|
||||
|
||||
mod buffered;
|
||||
mod uart_16550;
|
||||
|
||||
|
|
@ -5,4 +7,4 @@ pub use buffered::BufferedUart;
|
|||
pub use uart_16550::Uart16550Mmio;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use uart_16550::Uart16550Pio;
|
||||
pub use uart_16550::Uart16550Pmio;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use core::convert::TryInto;
|
|||
use core::ops::{BitAnd, BitOr, Not};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::io::{Io, Mmio, ReadOnly};
|
||||
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
|
||||
|
|
@ -106,6 +106,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// MMIO driver for UART 16550
|
||||
pub struct Uart16550Mmio<V: 'static>
|
||||
where
|
||||
V: Copy + BitAnd<Output = V> + BitOr<Output = V> + Not<Output = V>,
|
||||
|
|
@ -200,20 +201,21 @@ impl Uart16550Mmio<u32> {
|
|||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod pio {
|
||||
mod pmio {
|
||||
use super::*;
|
||||
use crate::io::Pio;
|
||||
use crate::io::Pmio;
|
||||
|
||||
pub struct Uart16550Pio {
|
||||
inner: Mutex<Uart16550Inner<Pio<u8>>>,
|
||||
/// Pmio driver for UART 16550
|
||||
pub struct Uart16550Pmio {
|
||||
inner: Mutex<Uart16550Inner<Pmio<u8>>>,
|
||||
listener: EventListener,
|
||||
}
|
||||
|
||||
impl_event_scheme!(Uart16550Pio);
|
||||
impl_event_scheme!(Uart16550Pmio);
|
||||
|
||||
impl Scheme for Uart16550Pio {
|
||||
impl Scheme for Uart16550Pmio {
|
||||
fn name(&self) -> &str {
|
||||
"uart16550-pio"
|
||||
"uart16550-Pmio"
|
||||
}
|
||||
|
||||
fn handle_irq(&self, _irq_num: usize) {
|
||||
|
|
@ -221,7 +223,7 @@ mod pio {
|
|||
}
|
||||
}
|
||||
|
||||
impl UartScheme for Uart16550Pio {
|
||||
impl UartScheme for Uart16550Pmio {
|
||||
fn try_recv(&self) -> DeviceResult<Option<u8>> {
|
||||
self.inner.lock().try_recv()
|
||||
}
|
||||
|
|
@ -235,16 +237,17 @@ mod pio {
|
|||
}
|
||||
}
|
||||
|
||||
impl Uart16550Pio {
|
||||
impl Uart16550Pmio {
|
||||
/// Construct a `Uart16550Pmio` whose address starts at `base`.
|
||||
pub fn new(base: u16) -> Self {
|
||||
let mut uart = Uart16550Inner::<Pio<u8>> {
|
||||
data: Pio::new(base),
|
||||
int_en: Pio::new(base + 1),
|
||||
fifo_ctrl: Pio::new(base + 2),
|
||||
line_ctrl: Pio::new(base + 3),
|
||||
modem_ctrl: Pio::new(base + 4),
|
||||
line_sts: ReadOnly::new(Pio::new(base + 5)),
|
||||
modem_sts: ReadOnly::new(Pio::new(base + 6)),
|
||||
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 {
|
||||
|
|
@ -256,4 +259,4 @@ mod pio {
|
|||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use pio::Uart16550Pio;
|
||||
pub use pmio::Uart16550Pmio;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use alloc::vec::Vec;
|
||||
use core::ops::Range;
|
||||
|
||||
use device_tree::{DeviceTree as DeviceTreeInner, PropError};
|
||||
//! 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};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,35 @@
|
|||
use alloc::{boxed::Box, vec::Vec};
|
||||
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
|
||||
/// A type alias for the closure to handle device event.
|
||||
pub type EventHandler<T = ()> = Box<dyn Fn(&T) + Send + Sync>;
|
||||
|
||||
/// Device event listener.
|
||||
///
|
||||
/// It keeps a series of [`EventHandler`]s that handle events of one single type.
|
||||
pub struct EventListener<T = ()> {
|
||||
events: Mutex<Vec<(EventHandler<T>, bool)>>,
|
||||
}
|
||||
|
||||
impl<T> EventListener<T> {
|
||||
/// Construct a new, empty `EventListener`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
events: Mutex::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a new `handler` into this `EventListener`.
|
||||
///
|
||||
/// If `once` is `true`, the `handler` will be removed once it handles an event.
|
||||
pub fn subscribe(&self, handler: EventHandler<T>, once: bool) {
|
||||
self.events.lock().push((handler, once));
|
||||
}
|
||||
|
||||
/// Send an event to the `EventListener`.
|
||||
///
|
||||
/// All the handlers handle the event, and those marked `once` will be removed immediately.
|
||||
pub fn trigger(&self, event: T) {
|
||||
self.events.lock().retain(|(f, once)| {
|
||||
f(&event);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Event handler and device tree.
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod event_listener;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
use virtio_drivers::{VirtIOBlk as InnerDriver, VirtIOHeader};
|
||||
|
||||
use crate::scheme::{BlockScheme, Scheme};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use core::fmt::{Result, Write};
|
||||
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
use virtio_drivers::{VirtIOConsole as InnerDriver, VirtIOHeader};
|
||||
|
||||
use crate::prelude::DeviceResult;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
use virtio_drivers::{VirtIOGpu as InnerDriver, VirtIOHeader};
|
||||
|
||||
use crate::prelude::{ColorFormat, DisplayInfo, FrameBuffer};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use core::convert::TryFrom;
|
||||
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
use virtio_drivers::{InputConfigSelect, VirtIOHeader, VirtIOInput as InnerDriver};
|
||||
|
||||
use crate::prelude::{CapabilityType, InputCapability, InputEvent, InputEventType};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Packaging of [`virtio-drivers` library](https://github.com/rcore-os/virtio-drivers).
|
||||
|
||||
mod blk;
|
||||
mod console;
|
||||
mod gpu;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
[package]
|
||||
name = "kernel-hal"
|
||||
version = "0.1.0"
|
||||
authors = ["Runji Wang <wangrunji0408@163.com>", "Yuekai Jia <equation618@gmail.com>"]
|
||||
authors = [
|
||||
"Runji Wang <wangrunji0408@163.com>",
|
||||
"Yuekai Jia <equation618@gmail.com>",
|
||||
]
|
||||
edition = "2018"
|
||||
description = "Kernel HAL interface definations."
|
||||
|
||||
|
|
@ -10,32 +13,40 @@ description = "Kernel HAL interface definations."
|
|||
[features]
|
||||
default = ["libos"]
|
||||
smp = []
|
||||
libos = ["nix", "tempfile", "async-std", "bitmap-allocator", "zcore-drivers/mock"]
|
||||
libos = [
|
||||
"nix",
|
||||
"tempfile",
|
||||
"async-std",
|
||||
"bitmap-allocator",
|
||||
"zcore-drivers/mock",
|
||||
]
|
||||
graphic = ["zcore-drivers/graphic"]
|
||||
|
||||
loopback = []
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
spin = "0.9"
|
||||
cfg-if = "1.0"
|
||||
bitflags = "1.3"
|
||||
trapframe = "0.9"
|
||||
trapframe = "0.9.0"
|
||||
git-version = "0.3"
|
||||
numeric-enum-macro = "0.2"
|
||||
lazy_static = { version = "1.4", features = ["spin_no_std"] }
|
||||
zcore-drivers = { path = "../drivers", features = ["virtio"] }
|
||||
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
|
||||
|
||||
lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "01b2e70" }
|
||||
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "async"] }
|
||||
|
||||
# LibOS mode
|
||||
[target.'cfg(not(target_os = "none"))'.dependencies]
|
||||
nix = { version = "0.23", optional = true }
|
||||
tempfile = { version = "3", optional = true }
|
||||
async-std = { version = "1.10", optional = true }
|
||||
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51", optional = true }
|
||||
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator.git", rev = "88e871a5", optional = true }
|
||||
|
||||
# Bare-metal mode
|
||||
[target.'cfg(target_os = "none")'.dependencies]
|
||||
executor = { git = "https://github.com/rcore-os/executor.git", rev = "85b9335" }
|
||||
executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler", rev = "3b04ba4" }
|
||||
naive-timer = "0.2.0"
|
||||
|
||||
# All mode on x86_64
|
||||
|
|
@ -48,7 +59,8 @@ x86_64 = "0.14"
|
|||
uefi = "0.11"
|
||||
raw-cpuid = "9.0"
|
||||
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "1069df3" }
|
||||
x2apic = "0.4"
|
||||
|
||||
# Bare-metal mode on riscv64
|
||||
[target.'cfg(all(target_os = "none", target_arch = "riscv64"))'.dependencies]
|
||||
riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }
|
||||
riscv = "0.8"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//! CPU information.
|
||||
|
||||
use crate::utils::init_once::InitOnce;
|
||||
|
||||
pub(super) static CPU_FREQ_MHZ: InitOnce<u16> = InitOnce::new_with_default(10);
|
||||
|
|
|
|||
|
|
@ -62,6 +62,37 @@ pub(super) fn init() -> DeviceResult {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "loopback"))]
|
||||
{
|
||||
use alloc::sync::Arc;
|
||||
use zcore_drivers::bus::pci;
|
||||
let pci_devs = pci::init(Some(Arc::new(IoMapperImpl)))?;
|
||||
for d in pci_devs.into_iter() {
|
||||
drivers::add_device(d);
|
||||
}
|
||||
}
|
||||
|
||||
intc_init()?;
|
||||
|
||||
#[cfg(feature = "graphic")]
|
||||
if let Some(display) = drivers::all_display().first() {
|
||||
crate::console::init_graphic_console(display.clone());
|
||||
if display.need_flush() {
|
||||
// TODO: support nested interrupt to render in time
|
||||
crate::thread::spawn(crate::common::future::DisplayFlushFuture::new(display, 30));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "loopback")]
|
||||
{
|
||||
use crate::net;
|
||||
net::init();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn intc_init() -> DeviceResult {
|
||||
let irq = drivers::all_irq()
|
||||
.find(format!("riscv-intc-cpu{}", crate::cpu::cpu_id()).as_str())
|
||||
.expect("IRQ device 'riscv-intc' not initialized!");
|
||||
|
|
@ -78,14 +109,5 @@ pub(super) fn init() -> DeviceResult {
|
|||
irq.unmask(ScauseIntCode::SupervisorSoft as _)?;
|
||||
irq.unmask(ScauseIntCode::SupervisorTimer as _)?;
|
||||
|
||||
#[cfg(feature = "graphic")]
|
||||
if let Some(display) = drivers::all_display().first() {
|
||||
crate::console::init_graphic_console(display.clone());
|
||||
if display.need_flush() {
|
||||
// TODO: support nested interrupt to render in time
|
||||
crate::thread::spawn(crate::common::future::DisplayFlushFuture::new(display, 30));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ use riscv::{asm, register::sstatus};
|
|||
hal_fn_impl! {
|
||||
impl mod crate::hal_fn::interrupt {
|
||||
fn wait_for_interrupt() {
|
||||
unsafe {
|
||||
// enable interrupt and disable
|
||||
sstatus::set_sie();
|
||||
asm::wfi();
|
||||
sstatus::clear_sie();
|
||||
let enable = sstatus::read().sie();
|
||||
if !enable {
|
||||
unsafe { sstatus::set_sie() };
|
||||
}
|
||||
unsafe { asm::wfi(); }
|
||||
if !enable {
|
||||
unsafe { sstatus::clear_sie() };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -17,5 +19,17 @@ hal_fn_impl! {
|
|||
trace!("Handle irq cause: {}", cause);
|
||||
crate::drivers::all_irq().first_unwrap().handle_irq(cause)
|
||||
}
|
||||
|
||||
fn intr_on() {
|
||||
unsafe { sstatus::set_sie() };
|
||||
}
|
||||
|
||||
fn intr_off() {
|
||||
unsafe { sstatus::clear_sie() };
|
||||
}
|
||||
|
||||
fn intr_get() -> bool {
|
||||
sstatus::read().sie()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@ pub fn free_pmem_regions() -> Vec<Range<PhysAddr>> {
|
|||
}
|
||||
if let Some(initrd) = initrd {
|
||||
// no overlap at all
|
||||
if initrd.end <= start || initrd.start >= end {
|
||||
if initrd.end <= start || end <= initrd.start {
|
||||
regions.push(start..end);
|
||||
continue;
|
||||
}
|
||||
// no overlap on the left
|
||||
if initrd.start > start {
|
||||
if start < initrd.start {
|
||||
regions.push(start..align_down(initrd.start));
|
||||
}
|
||||
// no overlap on the right
|
||||
|
|
|
|||
|
|
@ -9,9 +9,8 @@ pub mod sbi;
|
|||
pub mod timer;
|
||||
pub mod vm;
|
||||
|
||||
use alloc::{boxed::Box, format, string::String, vec::Vec};
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::ops::Range;
|
||||
use zcore_drivers::irq::riscv::ScauseIntCode;
|
||||
use zcore_drivers::utils::devicetree::Devicetree;
|
||||
|
||||
use crate::{mem::phys_to_virt, utils::init_once::InitOnce, PhysAddr};
|
||||
|
|
@ -20,6 +19,10 @@ static CMDLINE: InitOnce<String> = InitOnce::new_with_default(String::new());
|
|||
static INITRD_REGION: InitOnce<Option<Range<PhysAddr>>> = InitOnce::new_with_default(None);
|
||||
static MEMORY_REGIONS: InitOnce<Vec<Range<PhysAddr>>> = InitOnce::new_with_default(Vec::new());
|
||||
|
||||
pub const fn timer_interrupt_vector() -> usize {
|
||||
trap::SUPERVISOR_TIMER_INT_VEC
|
||||
}
|
||||
|
||||
pub fn cmdline() -> String {
|
||||
CMDLINE.clone()
|
||||
}
|
||||
|
|
@ -53,33 +56,19 @@ pub fn primary_init_early() {
|
|||
pub fn primary_init() {
|
||||
vm::init();
|
||||
drivers::init().unwrap();
|
||||
// We should set first time interrupt before run into first user program
|
||||
// timer::init();
|
||||
}
|
||||
|
||||
pub fn timer_init() {
|
||||
timer::init();
|
||||
}
|
||||
|
||||
pub fn secondary_init() {
|
||||
vm::init();
|
||||
let intc = crate::drivers::all_irq()
|
||||
.find(format!("riscv-intc-cpu{}", crate::cpu::cpu_id()).as_str())
|
||||
.expect("IRQ device 'riscv-intc' not initialized!");
|
||||
|
||||
// register soft interrupts handler
|
||||
intc.register_handler(
|
||||
ScauseIntCode::SupervisorSoft as _,
|
||||
Box::new(trap::super_soft),
|
||||
)
|
||||
.unwrap();
|
||||
// register timer interrupts handler
|
||||
intc.register_handler(
|
||||
ScauseIntCode::SupervisorTimer as _,
|
||||
Box::new(trap::super_timer),
|
||||
)
|
||||
.unwrap();
|
||||
intc.unmask(ScauseIntCode::SupervisorSoft as _).unwrap();
|
||||
intc.unmask(ScauseIntCode::SupervisorTimer as _).unwrap();
|
||||
|
||||
drivers::intc_init().unwrap();
|
||||
let plic = crate::drivers::all_irq()
|
||||
.find("riscv-plic")
|
||||
.expect("IRQ device 'riscv-plic' not initialized!");
|
||||
plic.init_hart();
|
||||
timer::init();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use riscv::register::scause;
|
|||
use trapframe::TrapFrame;
|
||||
|
||||
use crate::context::TrapReason;
|
||||
pub(super) const SUPERVISOR_TIMER_INT_VEC: usize = 5; // scause::Interrupt::SupervisorTimer
|
||||
|
||||
fn breakpoint(sepc: &mut usize) {
|
||||
info!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc);
|
||||
|
|
@ -14,7 +15,6 @@ fn breakpoint(sepc: &mut usize) {
|
|||
pub(super) fn super_timer() {
|
||||
super::timer::timer_set_next();
|
||||
crate::timer::timer_tick();
|
||||
|
||||
//发生外界中断时,epc的指令还没有执行,故无需修改epc到下一条
|
||||
}
|
||||
|
||||
|
|
@ -25,16 +25,22 @@ pub(super) fn super_soft() {
|
|||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
||||
// log::warn!("in trap handler");
|
||||
let scause = scause::read();
|
||||
trace!("kernel trap happened: {:?}", TrapReason::from(scause));
|
||||
trace!(
|
||||
"sepc = 0x{:x} pgtoken = 0x{:x}",
|
||||
tf.sepc,
|
||||
crate::vm::current_vmtoken()
|
||||
);
|
||||
match TrapReason::from(scause) {
|
||||
TrapReason::SoftwareBreakpoint => breakpoint(&mut tf.sepc),
|
||||
TrapReason::PageFault(vaddr, flags) => {
|
||||
// log::warn!("sepc={:x}", riscv::register::sepc::read());
|
||||
// log::warn!("sstatus.spp={:?}", riscv::register::sstatus::read().spp());
|
||||
crate::KHANDLER.handle_page_fault(vaddr, flags)
|
||||
TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags),
|
||||
TrapReason::Interrupt(vector) => {
|
||||
crate::interrupt::handle_irq(vector);
|
||||
if vector == SUPERVISOR_TIMER_INT_VEC {
|
||||
executor::handle_timeout();
|
||||
}
|
||||
}
|
||||
TrapReason::Interrupt(vector) => crate::interrupt::handle_irq(vector),
|
||||
other => panic!("Undefined trap: {:x?} {:#x?}", other, tf),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
use core::fmt::{Debug, Formatter, Result};
|
||||
use core::slice;
|
||||
|
||||
use lock::Mutex;
|
||||
use riscv::{asm, register::satp};
|
||||
use spin::Mutex;
|
||||
|
||||
use crate::utils::page_table::{GenericPTE, PageTableImpl, PageTableLevel3};
|
||||
use crate::{mem::phys_to_virt, MMUFlags, PhysAddr, VirtAddr, KCONFIG};
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ hal_fn_impl! {
|
|||
fn reset() -> ! {
|
||||
info!("shutdown...");
|
||||
loop {
|
||||
use zcore_drivers::io::{Io, Pio};
|
||||
Pio::<u16>::new(0x604).write(0x2000);
|
||||
use zcore_drivers::io::{Io, Pmio};
|
||||
Pmio::<u16>::new(0x604).write(0x2000);
|
||||
super::interrupt::wait_for_interrupt();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,16 @@ use alloc::{boxed::Box, sync::Arc};
|
|||
|
||||
use zcore_drivers::irq::x86::Apic;
|
||||
use zcore_drivers::scheme::IrqScheme;
|
||||
use zcore_drivers::uart::{BufferedUart, Uart16550Pio};
|
||||
use zcore_drivers::uart::{BufferedUart, Uart16550Pmio};
|
||||
use zcore_drivers::{Device, DeviceResult};
|
||||
|
||||
use super::trap;
|
||||
use crate::drivers;
|
||||
|
||||
pub(super) fn init_early() -> DeviceResult {
|
||||
let uart = Arc::new(Uart16550Pio::new(0x3F8));
|
||||
let uart = Arc::new(Uart16550Pmio::new(0x3F8));
|
||||
drivers::add_device(Device::Uart(BufferedUart::new(uart)));
|
||||
let uart = Arc::new(Uart16550Pmio::new(0x2F8));
|
||||
drivers::add_device(Device::Uart(BufferedUart::new(uart)));
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -20,14 +22,41 @@ pub(super) fn init() -> DeviceResult {
|
|||
super::special::pc_firmware_tables().0 as usize,
|
||||
crate::mem::phys_to_virt,
|
||||
));
|
||||
irq.register_device(
|
||||
trap::X86_ISA_IRQ_COM1,
|
||||
drivers::all_uart().first_unwrap().upcast(),
|
||||
)?;
|
||||
irq.unmask(trap::X86_ISA_IRQ_COM1)?;
|
||||
irq.register_local_apic_handler(trap::X86_INT_APIC_TIMER, Box::new(crate::timer::timer_tick))?;
|
||||
let uarts = drivers::all_uart();
|
||||
if let Some(u) = uarts.try_get(0) {
|
||||
irq.register_device(trap::X86_ISA_IRQ_COM1, u.clone().upcast())?;
|
||||
irq.unmask(trap::X86_ISA_IRQ_COM1)?;
|
||||
|
||||
if let Some(u) = uarts.try_get(1) {
|
||||
irq.register_device(trap::X86_ISA_IRQ_COM2, u.clone().upcast())?;
|
||||
irq.unmask(trap::X86_ISA_IRQ_COM2)?;
|
||||
}
|
||||
}
|
||||
|
||||
use x2apic::lapic::{TimerDivide, TimerMode};
|
||||
|
||||
irq.register_local_apic_handler(trap::X86_INT_APIC_TIMER, Box::new(super::trap::super_timer))?;
|
||||
|
||||
// SAFETY: this will be called once and only once for every core
|
||||
Apic::local_apic().set_timer_mode(TimerMode::Periodic);
|
||||
Apic::local_apic().set_timer_divide(TimerDivide::Div256); // indeed it is Div1, the name is confusing.
|
||||
let cycles =
|
||||
super::cpu::cpu_frequency() as u64 * 1_000_000 / super::super::timer::TICKS_PER_SEC;
|
||||
Apic::local_apic().set_timer_initial(cycles as u32);
|
||||
Apic::local_apic().disable_timer();
|
||||
|
||||
drivers::add_device(Device::Irq(irq));
|
||||
|
||||
#[cfg(not(feature = "loopback"))]
|
||||
{
|
||||
// PCI scan
|
||||
use zcore_drivers::bus::pci;
|
||||
let pci_devs = pci::init(None)?;
|
||||
for d in pci_devs.into_iter() {
|
||||
drivers::add_device(d);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "graphic")]
|
||||
{
|
||||
use crate::KCONFIG;
|
||||
|
|
@ -46,6 +75,12 @@ pub(super) fn init() -> DeviceResult {
|
|||
crate::console::init_graphic_console(display);
|
||||
}
|
||||
|
||||
#[cfg(feature = "loopback")]
|
||||
{
|
||||
use crate::net;
|
||||
net::init();
|
||||
}
|
||||
|
||||
info!("Drivers init end.");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,19 +5,34 @@ use core::ops::Range;
|
|||
use crate::drivers::all_irq;
|
||||
use crate::drivers::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
|
||||
use crate::HalResult;
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::hal_fn::interrupt {
|
||||
fn wait_for_interrupt() {
|
||||
use x86_64::instructions::interrupts;
|
||||
let enable = interrupts::are_enabled();
|
||||
interrupts::enable_and_hlt();
|
||||
interrupts::disable();
|
||||
if !enable {
|
||||
interrupts::disable();
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid_irq(gsi: usize) -> bool {
|
||||
all_irq().first_unwrap().is_valid_irq(gsi)
|
||||
}
|
||||
|
||||
fn intr_on() {
|
||||
interrupts::enable();
|
||||
}
|
||||
|
||||
fn intr_off() {
|
||||
interrupts::disable();
|
||||
}
|
||||
|
||||
fn intr_get() -> bool {
|
||||
interrupts::are_enabled()
|
||||
}
|
||||
|
||||
fn mask_irq(gsi: usize) -> HalResult {
|
||||
Ok(all_irq().first_unwrap().mask(gsi)?)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ hal_fn_impl_default!(crate::hal_fn::console);
|
|||
use crate::{mem::phys_to_virt, KCONFIG};
|
||||
use x86_64::registers::control::{Cr4, Cr4Flags};
|
||||
|
||||
pub const fn timer_interrupt_vector() -> usize {
|
||||
trap::X86_INT_APIC_TIMER
|
||||
}
|
||||
|
||||
pub fn cmdline() -> alloc::string::String {
|
||||
KCONFIG.cmdline.into()
|
||||
}
|
||||
|
|
@ -52,6 +56,10 @@ pub fn primary_init() {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn timer_init() {
|
||||
timer::init();
|
||||
}
|
||||
|
||||
pub fn secondary_init() {
|
||||
zcore_drivers::irq::x86::Apic::init_local_apic_ap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Functions only available on x86 platforms.
|
||||
|
||||
pub use zcore_drivers::io::{Io, Pio};
|
||||
pub use zcore_drivers::io::{Io, Pmio};
|
||||
|
||||
/// Get physical address of `acpi_rsdp` and `smbios` on x86_64.
|
||||
pub fn pc_firmware_tables() -> (u64, u64) {
|
||||
|
|
|
|||
|
|
@ -4,3 +4,8 @@ pub fn timer_now() -> Duration {
|
|||
let cycle = unsafe { core::arch::x86_64::_rdtsc() };
|
||||
Duration::from_nanos(cycle * 1000 / super::cpu::cpu_frequency() as u64)
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let irq = crate::drivers::all_irq().first_unwrap();
|
||||
irq.apic_timer_enable();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ fn breakpoint() {
|
|||
panic!("\nEXCEPTION: Breakpoint");
|
||||
}
|
||||
|
||||
pub(super) fn super_timer() {
|
||||
crate::timer::timer_tick();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
||||
trace!(
|
||||
|
|
@ -31,10 +35,16 @@ pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
|||
tf.trap_num,
|
||||
super::cpu::cpu_id()
|
||||
);
|
||||
|
||||
match TrapReason::from(tf.trap_num, tf.error_code) {
|
||||
TrapReason::HardwareBreakpoint | TrapReason::SoftwareBreakpoint => breakpoint(),
|
||||
TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags),
|
||||
TrapReason::Interrupt(vector) => crate::interrupt::handle_irq(vector),
|
||||
TrapReason::Interrupt(vector) => {
|
||||
crate::interrupt::handle_irq(vector);
|
||||
if vector == X86_INT_APIC_TIMER {
|
||||
executor::handle_timeout();
|
||||
}
|
||||
}
|
||||
other => panic!("Unhandled trap {:x?} {:#x?}", other, tf),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
//! Bootstrap and initialization.
|
||||
|
||||
use super::net;
|
||||
use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER};
|
||||
|
||||
hal_fn_impl! {
|
||||
|
|
@ -24,7 +23,6 @@ hal_fn_impl! {
|
|||
info!("Primary CPU {} init...", crate::cpu::cpu_id());
|
||||
unsafe { trapframe::init() };
|
||||
super::arch::primary_init();
|
||||
net::init();
|
||||
}
|
||||
|
||||
fn secondary_init() {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ cfg_if! {
|
|||
if #[cfg(target_arch = "x86_64")] {
|
||||
#[path = "arch/x86_64/mod.rs"]
|
||||
mod arch;
|
||||
pub use self::arch::special as x86_64;
|
||||
pub use self::arch::{special as x86_64, timer_interrupt_vector};
|
||||
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
|
||||
#[path = "arch/riscv/mod.rs"]
|
||||
pub mod arch;
|
||||
pub use self::arch::sbi;
|
||||
pub use self::arch::{sbi, timer_interrupt_vector};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// May need move to drivers
|
||||
use smoltcp::{
|
||||
iface::{InterfaceBuilder, NeighborCache, Route, Routes},
|
||||
phy::{Loopback, Medium},
|
||||
|
|
@ -11,7 +12,7 @@ use alloc::vec::Vec;
|
|||
use alloc::sync::Arc;
|
||||
|
||||
use alloc::string::String;
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
|
||||
use crate::drivers::add_device;
|
||||
use crate::drivers::all_net;
|
||||
|
|
|
|||
|
|
@ -3,18 +3,27 @@
|
|||
use alloc::boxed::Box;
|
||||
use core::time::Duration;
|
||||
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use lock::Mutex;
|
||||
use naive_timer::Timer;
|
||||
use spin::Mutex;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(super) const TICKS_PER_SEC: u64 = 100;
|
||||
|
||||
lazy_static! {
|
||||
static ref NAIVE_TIMER: Mutex<Timer> = Mutex::new(Timer::default());
|
||||
static ref FIRST: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::hal_fn::timer {
|
||||
fn timer_enable() {
|
||||
if !FIRST.load(Ordering::Relaxed) {
|
||||
FIRST.store(true, Ordering::Relaxed);
|
||||
super::arch::timer_init();
|
||||
}
|
||||
}
|
||||
|
||||
fn timer_now() -> Duration {
|
||||
super::arch::timer::timer_now()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate::drivers;
|
||||
use core::fmt::{Arguments, Result, Write};
|
||||
use spin::Mutex;
|
||||
use lock::Mutex;
|
||||
|
||||
struct SerialWriter;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ pub enum UserContextField {
|
|||
}
|
||||
|
||||
/// Reason of the trap.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum TrapReason {
|
||||
Syscall,
|
||||
Interrupt(usize),
|
||||
|
|
@ -39,6 +39,9 @@ pub enum TrapReason {
|
|||
GernelFault(usize),
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "libos"))]
|
||||
pub const TIMER_INTERRUPT_VEC: usize = crate::timer_interrupt_vector();
|
||||
|
||||
impl TrapReason {
|
||||
/// Get [`TrapReason`] from `trap_num` and `error_code` in trap frame for x86.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
|
@ -113,7 +116,7 @@ impl TrapReason {
|
|||
|
||||
/// User context saved on trap.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UserContext(UserContextInner);
|
||||
|
||||
impl UserContext {
|
||||
|
|
@ -124,35 +127,53 @@ impl UserContext {
|
|||
}
|
||||
|
||||
/// Initialize the context for entry into userspace.
|
||||
pub fn setup_uspace(&mut self, pc: usize, sp: usize, arg1: usize, arg2: usize) {
|
||||
/// Note: if the number of args < 3, please fill with zeros
|
||||
/// Eg: ctx.setup_uspace(pc_, sp_, &[arg1, arg2, 0])
|
||||
pub fn setup_uspace(&mut self, pc: usize, sp: usize, args: &[usize; 3]) {
|
||||
cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
self.0.general.rip = pc;
|
||||
self.0.general.rsp = sp;
|
||||
self.0.general.rdi = arg1;
|
||||
self.0.general.rsi = arg2;
|
||||
self.0.general.rdi = args[0];
|
||||
self.0.general.rsi = args[1];
|
||||
self.0.general.rdx = args[2];
|
||||
// IOPL = 3, IF = 1
|
||||
// FIXME: set IOPL = 0 when IO port bitmap is supporte
|
||||
self.0.general.rflags = 0x3000 | 0x200 | 0x2;
|
||||
} else if #[cfg(target_arch = "aarch64")] {
|
||||
self.0.elr = pc;
|
||||
self.0.sp = sp;
|
||||
self.0.general.x0 = arg1;
|
||||
self.0.general.x1 = arg2;
|
||||
self.0.general.x0 = args[0];
|
||||
self.0.general.x1 = args[1];
|
||||
self.0.general.x2 = args[2];
|
||||
// Mask SError exceptions (currently unhandled).
|
||||
// TODO
|
||||
self.0.spsr = 1 << 8;
|
||||
} else if #[cfg(target_arch = "riscv64")] {
|
||||
self.0.sepc = pc;
|
||||
self.0.general.sp = sp;
|
||||
self.0.general.a0 = arg1;
|
||||
self.0.general.a1 = arg2;
|
||||
self.0.general.a0 = args[0];
|
||||
self.0.general.a1 = args[1];
|
||||
self.0.general.a2 = args[2];
|
||||
// SUM = 1, FS = 0b11, SPIE = 1
|
||||
self.0.sstatus = 1 << 18 | 0b11 << 13 | 1 << 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Setup return addr
|
||||
pub fn set_ra(&mut self, _ra: usize) {
|
||||
cfg_if! {
|
||||
if #[cfg(target_arch = "riscv64")] {
|
||||
self.0.general.ra = _ra;
|
||||
} else if #[cfg(target_arch = "x86_64")] {
|
||||
error!("Please set return addr via stack!");
|
||||
} else {
|
||||
unimplemented!("Unsupported arch!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Switch to user mode.
|
||||
pub fn enter_uspace(&mut self) {
|
||||
cfg_if! {
|
||||
|
|
|
|||
|
|
@ -1,23 +1,42 @@
|
|||
//! Read/write user space pointer.
|
||||
// 来自用户空间的裸指针
|
||||
//! Raw pointer from user land.
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::{Debug, Formatter};
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use crate::VirtAddr;
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::{
|
||||
fmt::{Debug, Formatter},
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct UserPtr<T, P: Policy> {
|
||||
ptr: *mut T,
|
||||
mark: PhantomData<P>,
|
||||
}
|
||||
// 来自用户空间的裸指针
|
||||
/// Raw pointer from user land.
|
||||
#[repr(transparent)]
|
||||
pub struct UserPtr<T, P: Policy>(*mut T, PhantomData<P>);
|
||||
|
||||
// 标识用户指针功能的基特征。
|
||||
/// Base trait for Markers of user pointer policy.
|
||||
pub trait Policy {}
|
||||
|
||||
// 标记一个用于输入的指针。
|
||||
/// Marks a pointer used to read.
|
||||
pub trait Read: Policy {}
|
||||
|
||||
// 标记一个用于输出的指针。
|
||||
/// Marks a pointer used to write.
|
||||
pub trait Write: Policy {}
|
||||
pub enum In {}
|
||||
pub enum Out {}
|
||||
pub enum InOut {}
|
||||
|
||||
// 输入指针的类型参数。
|
||||
/// Type argument for user pointer used to read.
|
||||
pub struct In;
|
||||
|
||||
// 输出指针的类型参数。
|
||||
/// Type argument for user pointer used to write.
|
||||
pub struct Out;
|
||||
|
||||
// 既用于输入有用于输出的指针的类型参数。
|
||||
/// Type argument for user pointer used to both read and write.
|
||||
pub struct InOut;
|
||||
|
||||
impl Policy for In {}
|
||||
impl Policy for Out {}
|
||||
|
|
@ -31,9 +50,8 @@ pub type UserInPtr<T> = UserPtr<T, In>;
|
|||
pub type UserOutPtr<T> = UserPtr<T, Out>;
|
||||
pub type UserInOutPtr<T> = UserPtr<T, InOut>;
|
||||
|
||||
type Result<T> = core::result::Result<T, Error>;
|
||||
|
||||
/// The error type which is returned from user pointer.
|
||||
// 用户指针操作的异常类型。
|
||||
/// The error type which is returned from user pointer operation.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
InvalidUtf8,
|
||||
|
|
@ -43,9 +61,13 @@ pub enum Error {
|
|||
InvalidVectorAddress,
|
||||
}
|
||||
|
||||
// 本模块用到的只是用户指针操作结果的类型。
|
||||
type Result<T> = core::result::Result<T, Error>;
|
||||
|
||||
impl<T, P: Policy> Debug for UserPtr<T, P> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{:?}", self.ptr)
|
||||
// 打印用户指针就是打印裸指针
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,154 +76,210 @@ unsafe impl<T, P: Policy> Send for UserPtr<T, P> {}
|
|||
unsafe impl<T, P: Policy> Sync for UserPtr<T, P> {}
|
||||
|
||||
impl<T, P: Policy> From<usize> for UserPtr<T, P> {
|
||||
fn from(x: usize) -> Self {
|
||||
UserPtr {
|
||||
ptr: x as _,
|
||||
mark: PhantomData,
|
||||
}
|
||||
fn from(ptr: usize) -> Self {
|
||||
UserPtr(ptr as _, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P: Policy> UserPtr<T, P> {
|
||||
// 检查 `size` 是否足够放下一个 `T` 的值,
|
||||
// 并从 `addr` 构造一个用户指针。
|
||||
/// Checks if `size` is enough to save a value of `T`,
|
||||
/// then constructs a user pointer from its value `addr`.
|
||||
pub fn from_addr_size(addr: usize, size: usize) -> Result<Self> {
|
||||
if size < core::mem::size_of::<T>() {
|
||||
return Err(Error::BufferTooSmall);
|
||||
if size >= core::mem::size_of::<T>() {
|
||||
Ok(Self::from(addr))
|
||||
} else {
|
||||
Err(Error::BufferTooSmall)
|
||||
}
|
||||
Ok(Self::from(addr))
|
||||
}
|
||||
|
||||
// 如果指针为空,返回 `true`。
|
||||
/// Returns `true` if the pointer is null.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ptr.is_null()
|
||||
self.0.is_null()
|
||||
}
|
||||
|
||||
// 偏移指针。
|
||||
// `count` 表示 `T` 的数量;
|
||||
// 例如,`count` 为 3 表示将指针移动 `3 * size_of::<T>()` 个字节。
|
||||
/// Calculates the offset from a pointer.
|
||||
/// `count` is in units of `T`;
|
||||
/// e.g., a `count` of 3 represents a pointer offset of `3 * size_of::<T>()` bytes.
|
||||
pub fn add(&self, count: usize) -> Self {
|
||||
UserPtr {
|
||||
ptr: unsafe { self.ptr.add(count) },
|
||||
mark: PhantomData,
|
||||
}
|
||||
Self(unsafe { self.0.add(count) }, PhantomData)
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut T {
|
||||
self.ptr
|
||||
// 返回指针对应的虚地址。
|
||||
/// Returns the virtual address represented by the pointer.
|
||||
pub fn as_addr(&self) -> VirtAddr {
|
||||
self.0 as _
|
||||
}
|
||||
|
||||
// 检查用户指针是否合法。
|
||||
//
|
||||
// 如果指针非空且对齐则返回 `OK(())`。
|
||||
/// Checks avaliability of the user pointer.
|
||||
///
|
||||
/// Returns [`Ok(())`] if it is neither null nor unaligned.
|
||||
pub fn check(&self) -> Result<()> {
|
||||
if self.ptr.is_null() {
|
||||
return Err(Error::InvalidPointer);
|
||||
if !self.0.is_null() && (self.0 as usize) % core::mem::align_of::<T>() == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::InvalidPointer)
|
||||
}
|
||||
if (self.ptr as usize) % core::mem::align_of::<T>() != 0 {
|
||||
return Err(Error::InvalidPointer);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P: Read> UserPtr<T, P> {
|
||||
pub fn as_ref(&self) -> Result<&'static T> {
|
||||
Ok(unsafe { &*self.ptr })
|
||||
// 取出指针值的引用(不要用于小于 8 字节的类型)。
|
||||
/// Converts to reference.
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn as_ref(&self) -> &'static T {
|
||||
unsafe { &*self.0 }
|
||||
}
|
||||
|
||||
// 读取但不移动指针所指的值(通过逐字节拷贝,但不需要 `Copy` 特征)。
|
||||
// 指针所指的值保持不变。
|
||||
/// Reads the value from `self` without moving it.
|
||||
/// This leaves the memory in self unchanged.
|
||||
pub fn read(&self) -> Result<T> {
|
||||
// TODO: check ptr and return err
|
||||
self.check()?;
|
||||
Ok(unsafe { self.ptr.read() })
|
||||
Ok(unsafe { self.0.read() })
|
||||
}
|
||||
|
||||
// 和读取一样,
|
||||
// 但若指针为空,返回 `None`。
|
||||
/// Same as [`read`](Self::read),
|
||||
/// but returns [`None`] when pointer is null.
|
||||
pub fn read_if_not_null(&self) -> Result<Option<T>> {
|
||||
if self.ptr.is_null() {
|
||||
return Ok(None);
|
||||
if !self.0.is_null() {
|
||||
Ok(Some(self.read()?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
let value = self.read()?;
|
||||
Ok(Some(value))
|
||||
}
|
||||
|
||||
// 构造一个从指针指向开始,长度为 `len` 的切片。
|
||||
/// Forms a slice from a user pointer and a `len`.
|
||||
pub fn as_slice(&self, len: usize) -> Result<&'static [T]> {
|
||||
if len == 0 {
|
||||
Ok(&[])
|
||||
} else {
|
||||
self.check()?;
|
||||
Ok(unsafe { core::slice::from_raw_parts(self.0, len) })
|
||||
}
|
||||
}
|
||||
|
||||
// 拷贝对象来构造一个 `Vec`。
|
||||
//
|
||||
// `len` 是成员的数量,而不是字节数。
|
||||
/// Copies elements into a new [`Vec`].
|
||||
///
|
||||
/// The `len` argument is the number of **elements**, not the number of bytes.
|
||||
pub fn read_array(&self, len: usize) -> Result<Vec<T>> {
|
||||
if len == 0 {
|
||||
return Ok(Vec::default());
|
||||
Ok(Vec::default())
|
||||
} else {
|
||||
self.check()?;
|
||||
let mut ret = Vec::<T>::with_capacity(len);
|
||||
unsafe {
|
||||
ret.set_len(len);
|
||||
ret.as_mut_ptr().copy_from_nonoverlapping(self.0, len);
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
self.check()?;
|
||||
let mut ret = Vec::<T>::with_capacity(len);
|
||||
unsafe {
|
||||
ret.set_len(len);
|
||||
ret.as_mut_ptr().copy_from_nonoverlapping(self.ptr, len);
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Read> UserPtr<u8, P> {
|
||||
pub fn read_string(&self, len: usize) -> Result<String> {
|
||||
self.check()?;
|
||||
let src = unsafe { core::slice::from_raw_parts(self.ptr, len) };
|
||||
let s = core::str::from_utf8(src).map_err(|_| Error::InvalidUtf8)?;
|
||||
Ok(String::from(s))
|
||||
// 构造一个从指针指向开始,长度为 `len` 的字符切片。
|
||||
/// Forms an utf-8 string slice from a user pointer and a `len`.
|
||||
pub fn as_str(&self, len: usize) -> Result<&'static str> {
|
||||
core::str::from_utf8(self.as_slice(len)?).map_err(|_| Error::InvalidUtf8)
|
||||
}
|
||||
|
||||
pub fn read_cstring(&self) -> Result<String> {
|
||||
self.check()?;
|
||||
let len = unsafe { (0usize..).find(|&i| *self.ptr.add(i) == 0).unwrap() };
|
||||
self.read_string(len)
|
||||
// 从一个 C 风格的零结尾字符串构造一个字符切片。
|
||||
/// Forms a zero-terminated string slice from a user pointer to a c style string.
|
||||
pub fn as_c_str(&self) -> Result<&'static str> {
|
||||
self.as_str(unsafe { (0usize..).find(|&i| *self.0.add(i) == 0).unwrap() })
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Read> UserPtr<UserPtr<u8, P>, P> {
|
||||
impl<P: 'static + Read> UserPtr<UserPtr<u8, P>, P> {
|
||||
// 拷贝一组 C 风格的零结尾字符串到 `String`,
|
||||
// 并收集到一个 `Vec` 中。
|
||||
/// Copies a group of zero-terminated string into [`String`]s,
|
||||
/// and collect them into a [`Vec`].
|
||||
pub fn read_cstring_array(&self) -> Result<Vec<String>> {
|
||||
self.check()?;
|
||||
let len = unsafe {
|
||||
(0usize..)
|
||||
.find(|&i| self.ptr.add(i).read().is_null())
|
||||
.unwrap()
|
||||
};
|
||||
self.read_array(len)?
|
||||
.into_iter()
|
||||
.map(|ptr| ptr.read_cstring())
|
||||
.collect()
|
||||
let mut result = Vec::new();
|
||||
let mut pptr = self.0;
|
||||
loop {
|
||||
let sptr = unsafe { pptr.read() };
|
||||
if sptr.is_null() {
|
||||
break;
|
||||
}
|
||||
result.push(sptr.as_c_str()?.into());
|
||||
pptr = unsafe { pptr.add(1) };
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P: Write> UserPtr<T, P> {
|
||||
// 用指定的值覆盖指针位置。
|
||||
// 旧的值直接被覆盖,不会调用释放逻辑。
|
||||
/// Overwrites a memory location with the given `value`
|
||||
/// **without** reading or dropping the old value.
|
||||
pub fn write(&mut self, value: T) -> Result<()> {
|
||||
self.check()?;
|
||||
unsafe {
|
||||
self.ptr.write(value);
|
||||
}
|
||||
unsafe { self.0.write(value) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// 类似于写,
|
||||
// 但指针为空时返回 `Ok(())`。
|
||||
/// Same as [`write`](Self::write),
|
||||
/// but does nothing and returns [`Ok`] when pointer is null.
|
||||
pub fn write_if_not_null(&mut self, value: T) -> Result<()> {
|
||||
if self.ptr.is_null() {
|
||||
return Ok(());
|
||||
if !self.0.is_null() {
|
||||
self.write(value)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
self.write(value)
|
||||
}
|
||||
|
||||
// 写入 `values.len() * size_of<T>` 字节到指针位置。
|
||||
// 写入的区间与目标区间不可重叠。
|
||||
/// Copies `values.len() * size_of<T>` bytes from `values` to `self`.
|
||||
/// The source and destination may not overlap.
|
||||
pub fn write_array(&mut self, values: &[T]) -> Result<()> {
|
||||
if values.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
self.check()?;
|
||||
unsafe {
|
||||
self.ptr
|
||||
.copy_from_nonoverlapping(values.as_ptr(), values.len());
|
||||
if !values.is_empty() {
|
||||
self.check()?;
|
||||
unsafe {
|
||||
self.0
|
||||
.copy_from_nonoverlapping(values.as_ptr(), values.len())
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Write> UserPtr<u8, P> {
|
||||
// 拷贝指定字符串到目标位置并写入一个 `\0` 来模拟 C 风格零结尾字符串。
|
||||
/// Copies `s` to `self`, then write a `'\0'` for c style string.
|
||||
pub fn write_cstring(&mut self, s: &str) -> Result<()> {
|
||||
let bytes = s.as_bytes();
|
||||
self.write_array(bytes)?;
|
||||
unsafe {
|
||||
self.ptr.add(bytes.len()).write(0);
|
||||
}
|
||||
unsafe { self.0.add(bytes.len()).write(0) };
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct IoVec<P: Policy> {
|
||||
pub struct IoVec<P: 'static + Policy> {
|
||||
/// Starting address
|
||||
ptr: UserPtr<u8, P>,
|
||||
/// Number of bytes to transfer
|
||||
|
|
@ -213,13 +291,13 @@ pub type IoVecOut = IoVec<Out>;
|
|||
|
||||
/// A valid IoVecs request from user
|
||||
#[derive(Debug)]
|
||||
pub struct IoVecs<P: Policy> {
|
||||
pub struct IoVecs<P: 'static + Policy> {
|
||||
vec: Vec<IoVec<P>>,
|
||||
}
|
||||
|
||||
impl<P: Policy> UserInPtr<IoVec<P>> {
|
||||
pub fn read_iovecs(&self, count: usize) -> Result<IoVecs<P>> {
|
||||
if self.ptr.is_null() {
|
||||
if self.0.is_null() {
|
||||
return Err(Error::InvalidPointer);
|
||||
}
|
||||
let vec = self.read_array(count)?;
|
||||
|
|
@ -246,7 +324,7 @@ impl<P: Read> IoVecs<P> {
|
|||
pub fn read_to_vec(&self) -> Result<Vec<u8>> {
|
||||
let mut buf = Vec::new();
|
||||
for vec in self.vec.iter() {
|
||||
buf.extend(vec.ptr.read_array(vec.len)?);
|
||||
buf.extend_from_slice(vec.ptr.as_slice(vec.len)?);
|
||||
}
|
||||
Ok(buf)
|
||||
}
|
||||
|
|
@ -299,20 +377,14 @@ impl<P: Policy> IoVec<P> {
|
|||
}
|
||||
|
||||
pub fn as_slice(&self) -> Result<&[u8]> {
|
||||
if self.ptr.is_null() {
|
||||
return Err(Error::InvalidVectorAddress);
|
||||
}
|
||||
let slice = unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) };
|
||||
Ok(slice)
|
||||
self.as_mut_slice().map(|s| &*s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Write> IoVec<P> {
|
||||
pub fn as_mut_slice(&mut self) -> Result<&mut [u8]> {
|
||||
if self.ptr.is_null() {
|
||||
return Err(Error::InvalidVectorAddress);
|
||||
pub fn as_mut_slice(&self) -> Result<&mut [u8]> {
|
||||
if !self.ptr.is_null() {
|
||||
Ok(unsafe { core::slice::from_raw_parts_mut(self.ptr.0, self.len) })
|
||||
} else {
|
||||
Err(Error::InvalidVectorAddress)
|
||||
}
|
||||
let slice = unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) };
|
||||
Ok(slice)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use alloc::{sync::Arc, vec::Vec};
|
||||
use core::convert::From;
|
||||
|
||||
use spin::{RwLock, RwLockReadGuard};
|
||||
use lock::{RwLock, RwLockReadGuard};
|
||||
|
||||
use zcore_drivers::scheme::{
|
||||
BlockScheme, DisplayScheme, InputScheme, IrqScheme, NetScheme, Scheme, UartScheme,
|
||||
|
|
|
|||
|
|
@ -97,6 +97,15 @@ hal_fn_def! {
|
|||
/// Is a valid IRQ number.
|
||||
pub fn is_valid_irq(vector: usize) -> bool;
|
||||
|
||||
/// Enable the interrupts
|
||||
pub fn intr_on();
|
||||
|
||||
/// Disable the interrupts
|
||||
pub fn intr_off();
|
||||
|
||||
/// Test weather interrupt is enabled
|
||||
pub fn intr_get() -> bool;
|
||||
|
||||
/// Disable IRQ.
|
||||
pub fn mask_irq(vector: usize) -> HalResult;
|
||||
|
||||
|
|
@ -148,6 +157,9 @@ hal_fn_def! {
|
|||
|
||||
/// Time and clock functions.
|
||||
pub mod timer {
|
||||
/// Set the first time interrupt
|
||||
pub fn timer_enable();
|
||||
|
||||
/// Get current time.
|
||||
/// TODO: use `Instant` as return type.
|
||||
pub fn timer_now() -> Duration;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
//! Bootstrap and initialization.
|
||||
|
||||
use super::net;
|
||||
use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER};
|
||||
|
||||
hal_fn_impl! {
|
||||
|
|
@ -19,7 +18,6 @@ hal_fn_impl! {
|
|||
super::macos::register_sigsegv_handler();
|
||||
}
|
||||
|
||||
net::init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,4 +45,10 @@ pub(super) fn init() {
|
|||
|
||||
crate::console::init_graphic_console(display);
|
||||
}
|
||||
|
||||
#[cfg(feature = "loopback")]
|
||||
{
|
||||
use crate::net;
|
||||
net::init();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
hal_fn_impl! {
|
||||
impl mod crate::hal_fn::interrupt {
|
||||
fn wait_for_interrupt() {}
|
||||
fn intr_on() {}
|
||||
fn intr_off() {}
|
||||
fn intr_get() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ mod mock_mem;
|
|||
pub mod boot;
|
||||
pub mod config;
|
||||
pub mod cpu;
|
||||
pub mod interrupt;
|
||||
pub mod mem;
|
||||
pub mod net;
|
||||
pub mod thread;
|
||||
|
|
@ -16,9 +17,9 @@ pub mod vm;
|
|||
#[doc(cfg(feature = "libos"))]
|
||||
pub mod libos;
|
||||
|
||||
pub use super::hal_fn::{interrupt, rand};
|
||||
pub use super::hal_fn::rand;
|
||||
|
||||
hal_fn_impl_default!(interrupt, rand, super::hal_fn::console);
|
||||
hal_fn_impl_default!(rand, super::hal_fn::console);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// May need move to drivers
|
||||
use smoltcp::{
|
||||
iface::{InterfaceBuilder, NeighborCache, Route, Routes},
|
||||
phy::{Loopback, Medium},
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ impl GenericPageTable for PageTable {
|
|||
|
||||
fn query(&self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, MMUFlags, PageSize)> {
|
||||
debug_assert!(is_aligned(vaddr));
|
||||
if PMEM_MAP_VADDR <= vaddr && vaddr < PMEM_MAP_VADDR + PMEM_SIZE {
|
||||
if (PMEM_MAP_VADDR..PMEM_MAP_VADDR + PMEM_SIZE).contains(&vaddr) {
|
||||
Ok((
|
||||
vaddr - PMEM_MAP_VADDR,
|
||||
MMUFlags::READ | MMUFlags::WRITE,
|
||||
|
|
@ -95,7 +95,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
/// A valid virtual address base to mmap.
|
||||
const VBASE: VirtAddr = 0x2_00000000;
|
||||
const VBASE: VirtAddr = 0x0002_0000_0000;
|
||||
|
||||
#[test]
|
||||
fn map_unmap() {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use core::{fmt::Debug, marker::PhantomData, slice};
|
|||
use crate::common::vm::*;
|
||||
use crate::{mem::PhysFrame, MMUFlags, PhysAddr, VirtAddr};
|
||||
|
||||
use lock::Mutex;
|
||||
|
||||
pub trait PageTableLevel: Sync + Send {
|
||||
const LEVEL: usize;
|
||||
}
|
||||
|
|
@ -150,7 +152,7 @@ impl<L: PageTableLevel, PTE: GenericPTE> PageTableImpl<L, PTE> {
|
|||
}
|
||||
|
||||
fn dump(&self, limit: usize, print_fn: impl Fn(core::fmt::Arguments)) {
|
||||
static LOCK: spin::Mutex<()> = spin::Mutex::new(());
|
||||
static LOCK: Mutex<()> = Mutex::new(());
|
||||
let _lock = LOCK.lock();
|
||||
|
||||
print_fn(format_args!("Root: {:x?}\n", self.table_phys()));
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 1426bea9f3482dec1aa98c31dcc3733a750fb090
|
||||
|
|
@ -19,11 +19,18 @@ zircon-object = { path = "../zircon-object", features = ["elf"] }
|
|||
kernel-hal = { path = "../kernel-hal", default-features = false }
|
||||
downcast-rs = { version = "1.2", default-features = false }
|
||||
lazy_static = { version = "1.4", features = ["spin_no_std"] }
|
||||
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
|
||||
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
|
||||
rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
|
||||
rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
|
||||
rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
|
||||
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
|
||||
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
|
||||
rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
|
||||
rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
|
||||
rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
|
||||
cfg-if = "1.0"
|
||||
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
|
||||
zcore-drivers = { path = "../drivers", features = ["virtio"] }
|
||||
zcore-drivers = { path = "../drivers", features = ["virtio"] }
|
||||
lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "01b2e70" }
|
||||
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "async"] }
|
||||
|
||||
# LibOS mode
|
||||
[target.'cfg(not(target_os = "none"))'.dependencies]
|
||||
|
||||
# Bare-metal mode
|
||||
[target.'cfg(target_os = "none")'.dependencies]
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ pub enum LxError {
|
|||
EISCONN = 106,
|
||||
/// Transport endpoint is not connected
|
||||
ENOTCONN = 107,
|
||||
/// Connection timeout
|
||||
ETIMEDOUT = 110,
|
||||
/// Connection refused
|
||||
ECONNREFUSED = 111,
|
||||
}
|
||||
|
|
@ -184,6 +186,7 @@ impl From<ZxError> for LxError {
|
|||
ZxError::SHOULD_WAIT => LxError::EAGAIN,
|
||||
ZxError::PEER_CLOSED => LxError::EPIPE,
|
||||
ZxError::BAD_HANDLE => LxError::EBADF,
|
||||
ZxError::TIMED_OUT => LxError::ETIMEDOUT,
|
||||
_ => unimplemented!("unknown error type: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
mod fbdev;
|
||||
mod input;
|
||||
mod random;
|
||||
mod uartdev;
|
||||
|
||||
pub use fbdev::FbDev;
|
||||
pub use input::{EventDev, MiceDev};
|
||||
pub use random::RandomINode;
|
||||
pub use uartdev::UartDev;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
use alloc::sync::Arc;
|
||||
use core::any::Any;
|
||||
use rcore_fs::vfs::{make_rdev, FileType, FsError, INode, Metadata, PollStatus, Result, Timespec};
|
||||
use rcore_fs_devfs::DevFS;
|
||||
use zcore_drivers::{scheme::UartScheme, DeviceError};
|
||||
|
||||
/// Uart device.
|
||||
pub struct UartDev {
|
||||
index: usize,
|
||||
port: Arc<dyn UartScheme>,
|
||||
inode_id: usize,
|
||||
}
|
||||
|
||||
impl UartDev {
|
||||
pub fn new(index: usize, port: Arc<dyn UartScheme>) -> Self {
|
||||
Self {
|
||||
index,
|
||||
port,
|
||||
inode_id: DevFS::new_inode_id(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl INode for UartDev {
|
||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
info!(
|
||||
"uart read_at: offset={:#x} buf_len={:#x}",
|
||||
offset,
|
||||
buf.len()
|
||||
);
|
||||
|
||||
let mut len = 0;
|
||||
for b in buf.iter_mut() {
|
||||
match self.port.try_recv() {
|
||||
Ok(Some(b_)) => {
|
||||
*b = b_;
|
||||
len += 1;
|
||||
}
|
||||
Ok(None) => break,
|
||||
Err(e) => return Err(convert_error(e)),
|
||||
}
|
||||
}
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
info!(
|
||||
"uart write_at: offset={:#x} buf_len={:#x}",
|
||||
offset,
|
||||
buf.len()
|
||||
);
|
||||
|
||||
for b in buf {
|
||||
self.port.send(*b).map_err(convert_error)?;
|
||||
}
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn poll(&self) -> Result<PollStatus> {
|
||||
Ok(PollStatus {
|
||||
// TOKNOW and TODO
|
||||
read: true,
|
||||
write: false,
|
||||
error: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Result<Metadata> {
|
||||
Ok(Metadata {
|
||||
dev: 1,
|
||||
inode: self.inode_id,
|
||||
size: 0,
|
||||
blk_size: 0,
|
||||
blocks: 0,
|
||||
atime: Timespec { sec: 0, nsec: 0 },
|
||||
mtime: Timespec { sec: 0, nsec: 0 },
|
||||
ctime: Timespec { sec: 0, nsec: 0 },
|
||||
type_: FileType::CharDevice,
|
||||
mode: 0o600, // owner read & write
|
||||
nlinks: 1,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
rdev: make_rdev(4, self.index),
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
fn io_control(&self, _cmd: u32, _data: usize) -> Result<usize> {
|
||||
warn!("uart ioctl unimplemented");
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_error(e: DeviceError) -> FsError {
|
||||
match e {
|
||||
DeviceError::NotSupported => FsError::NotSupported,
|
||||
DeviceError::NotReady => FsError::Busy,
|
||||
DeviceError::InvalidParam => FsError::InvalidParam,
|
||||
DeviceError::BufferTooSmall
|
||||
| DeviceError::DmaError
|
||||
| DeviceError::IoError
|
||||
| DeviceError::AlreadyExists
|
||||
| DeviceError::NoResources => FsError::DeviceError,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
//! Implement Device
|
||||
|
||||
use rcore_fs::dev::{Device, Result};
|
||||
use spin::RwLock;
|
||||
use lock::RwLock;
|
||||
|
||||
/// memory buffer for device
|
||||
pub struct MemBuf(RwLock<&'static mut [u8]>);
|
||||
|
|
|
|||
|
|
@ -17,15 +17,18 @@ use downcast_rs::impl_downcast;
|
|||
|
||||
use kernel_hal::drivers;
|
||||
use rcore_fs::vfs::{FileSystem, FileType, INode, PollStatus, Result};
|
||||
use rcore_fs_devfs::special::{NullINode, ZeroINode};
|
||||
use rcore_fs_devfs::DevFS;
|
||||
use rcore_fs_devfs::{
|
||||
special::{NullINode, ZeroINode},
|
||||
DevFS,
|
||||
};
|
||||
use rcore_fs_mountfs::MountFS;
|
||||
use rcore_fs_ramfs::RamFS;
|
||||
use zircon_object::{object::KernelObject, vm::VmObject};
|
||||
|
||||
use self::{devfs::RandomINode, pseudo::Pseudo};
|
||||
use crate::error::{LxError, LxResult};
|
||||
use crate::process::LinuxProcess;
|
||||
use devfs::RandomINode;
|
||||
use pseudo::Pseudo;
|
||||
|
||||
pub use file::{File, OpenFlags, SeekFrom};
|
||||
pub use pipe::Pipe;
|
||||
|
|
@ -126,9 +129,11 @@ pub fn create_root_fs(rootfs: Arc<dyn FileSystem>) -> Arc<dyn INode> {
|
|||
devfs_root
|
||||
.add("urandom", Arc::new(RandomINode::new(true)))
|
||||
.expect("failed to mknod /dev/urandom");
|
||||
|
||||
devfs_root
|
||||
.add("shm", Arc::new(RandomINode::new(true)))
|
||||
.expect("failed to mknod /dev/shm");
|
||||
if let Some(display) = drivers::all_display().first() {
|
||||
use self::devfs::{EventDev, FbDev, MiceDev};
|
||||
use devfs::{EventDev, FbDev, MiceDev};
|
||||
|
||||
// Add framebuffer device at `/dev/fb0`
|
||||
if let Err(e) = devfs_root.add("fb0", Arc::new(FbDev::new(display.clone()))) {
|
||||
|
|
@ -156,6 +161,14 @@ pub fn create_root_fs(rootfs: Arc<dyn FileSystem>) -> Arc<dyn INode> {
|
|||
}
|
||||
}
|
||||
|
||||
// Add uart devices at `/dev/ttyS{i}`
|
||||
for (i, uart) in drivers::all_uart().as_vec().iter().enumerate() {
|
||||
let fname = format!("ttyS{}", i);
|
||||
if let Err(e) = devfs_root.add(&fname, Arc::new(devfs::UartDev::new(i, uart.clone()))) {
|
||||
warn!("failed to mknod /dev/{}: {:?}", &fname, e);
|
||||
}
|
||||
}
|
||||
|
||||
// mount DevFS at /dev
|
||||
let dev = root.find(true, "dev").unwrap_or_else(|_| {
|
||||
root.create("dev", FileType::Dir, 0o666)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ use core::pin::Pin;
|
|||
use core::task::{Context, Poll};
|
||||
use kernel_hal::console::{self, ConsoleWinSize};
|
||||
use lazy_static::lazy_static;
|
||||
use lock::Mutex;
|
||||
use rcore_fs::vfs::*;
|
||||
use spin::Mutex;
|
||||
|
||||
lazy_static! {
|
||||
/// STDIN global reference
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ pub use self::shared_mem::*;
|
|||
use alloc::collections::BTreeMap;
|
||||
use alloc::sync::Arc;
|
||||
use bitflags::*;
|
||||
use spin::Mutex;
|
||||
|
||||
/// Semaphore table in a process
|
||||
#[derive(Default)]
|
||||
|
|
@ -130,7 +131,7 @@ impl Drop for SemProc {
|
|||
|
||||
impl ShmProc {
|
||||
/// Insert the `SharedGuard` and return its ID
|
||||
pub fn add(&mut self, shared_guard: Arc<spin::Mutex<ShmGuard>>) -> ShmId {
|
||||
pub fn add(&mut self, shared_guard: Arc<Mutex<ShmGuard>>) -> ShmId {
|
||||
let id = self.get_free_id();
|
||||
let shm_identifier = ShmIdentifier {
|
||||
addr: 0,
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ use crate::time::*;
|
|||
use alloc::{collections::BTreeMap, sync::Arc, sync::Weak, vec::Vec};
|
||||
use core::ops::Index;
|
||||
use lazy_static::*;
|
||||
use spin::Mutex;
|
||||
use spin::RwLock;
|
||||
use spin::{Mutex, RwLock};
|
||||
|
||||
/// semid data structure
|
||||
///
|
||||
|
|
|
|||
|
|
@ -4,13 +4,11 @@ use crate::error::LxError;
|
|||
use crate::time::TimeSpec;
|
||||
use alloc::{collections::BTreeMap, sync::Arc, sync::Weak};
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use spin::RwLock;
|
||||
use spin::{Mutex, RwLock};
|
||||
use zircon_object::vm::*;
|
||||
|
||||
lazy_static! {
|
||||
static ref KEY2SHM: RwLock<BTreeMap<u32, Weak<spin::Mutex<ShmGuard>>>> =
|
||||
RwLock::new(BTreeMap::new());
|
||||
static ref KEY2SHM: RwLock<BTreeMap<u32, Weak<Mutex<ShmGuard>>>> = RwLock::new(BTreeMap::new());
|
||||
}
|
||||
|
||||
/// shmid data structure
|
||||
|
|
@ -43,7 +41,7 @@ pub struct ShmIdentifier {
|
|||
/// Shared memory address
|
||||
pub addr: usize,
|
||||
/// Shared memory buffer and data
|
||||
pub guard: Arc<spin::Mutex<ShmGuard>>,
|
||||
pub guard: Arc<Mutex<ShmGuard>>,
|
||||
}
|
||||
|
||||
/// shared memory buffer and data
|
||||
|
|
@ -66,7 +64,7 @@ impl ShmIdentifier {
|
|||
memsize: usize,
|
||||
flags: usize,
|
||||
cpid: u32,
|
||||
) -> Result<Arc<spin::Mutex<ShmGuard>>, LxError> {
|
||||
) -> Result<Arc<Mutex<ShmGuard>>, LxError> {
|
||||
let mut key2shm = KEY2SHM.write();
|
||||
let flag = IpcGetFlag::from_bits_truncate(flags);
|
||||
|
||||
|
|
@ -80,7 +78,7 @@ impl ShmIdentifier {
|
|||
return Ok(guard);
|
||||
}
|
||||
}
|
||||
let shared_guard = Arc::new(spin::Mutex::new(ShmGuard {
|
||||
let shared_guard = Arc::new(Mutex::new(ShmGuard {
|
||||
shared_guard: VmObject::new_paged(pages(memsize)),
|
||||
shmid_ds: Mutex::new(ShmidDs {
|
||||
perm: IpcPerm {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
/// missing documentation
|
||||
pub mod socket_address;
|
||||
use smoltcp::wire::IpEndpoint;
|
||||
pub use socket_address::*;
|
||||
|
||||
/// missing documentation
|
||||
|
|
@ -14,6 +15,7 @@ pub mod udp;
|
|||
pub use udp::*;
|
||||
|
||||
use spin::Mutex;
|
||||
|
||||
/// missing documentation
|
||||
// pub mod raw;
|
||||
// pub use raw::*;
|
||||
|
|
@ -111,24 +113,8 @@ impl Drop for GlobalSocketHandle {
|
|||
}
|
||||
}
|
||||
|
||||
// #[cfg(feature = "e1000")]
|
||||
use kernel_hal::net::get_net_device;
|
||||
|
||||
#[cfg(feature = "loopback")]
|
||||
use hashbrown::HashMap;
|
||||
#[cfg(feature = "loopback")]
|
||||
use kernel_hal::timer_now;
|
||||
// #[cfg(feature = "loopback")]
|
||||
// use net_stack::{NetStack, NET_STACK};
|
||||
#[cfg(feature = "loopback")]
|
||||
use smoltcp::time::Instant;
|
||||
|
||||
// /// miss doc
|
||||
// #[cfg(feature = "loopback")]
|
||||
// pub fn get_net_stack() -> HashMap<usize, Arc<dyn NetStack>> {
|
||||
// NET_STACK.read().clone()
|
||||
// }
|
||||
|
||||
/// miss doc
|
||||
fn poll_ifaces() {
|
||||
for iface in get_net_device().iter() {
|
||||
|
|
@ -141,67 +127,8 @@ fn poll_ifaces() {
|
|||
}
|
||||
}
|
||||
|
||||
// use core::future::Future;
|
||||
// use core::pin::Pin;
|
||||
// use core::task::Context;
|
||||
// use core::task::Poll;
|
||||
|
||||
// use smoltcp::socket::TcpSocket;
|
||||
|
||||
// ============= SocketHandle =============
|
||||
|
||||
// ============= Endpoint =============
|
||||
|
||||
use smoltcp::wire::IpEndpoint;
|
||||
|
||||
/// missing documentation
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Endpoint {
|
||||
/// missing documentation
|
||||
Ip(IpEndpoint),
|
||||
/// missing documentation
|
||||
LinkLevel(LinkLevelEndpoint),
|
||||
/// missing documentation
|
||||
Netlink(NetlinkEndpoint),
|
||||
}
|
||||
|
||||
/// missing documentation
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LinkLevelEndpoint {
|
||||
/// missing documentation
|
||||
pub interface_index: usize,
|
||||
}
|
||||
|
||||
impl LinkLevelEndpoint {
|
||||
/// missing documentation
|
||||
pub fn new(ifindex: usize) -> Self {
|
||||
LinkLevelEndpoint {
|
||||
interface_index: ifindex,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// missing documentation
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NetlinkEndpoint {
|
||||
/// missing documentation
|
||||
pub port_id: u32,
|
||||
/// missing documentation
|
||||
pub multicast_groups_mask: u32,
|
||||
}
|
||||
|
||||
impl NetlinkEndpoint {
|
||||
/// missing documentation
|
||||
pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self {
|
||||
NetlinkEndpoint {
|
||||
port_id,
|
||||
multicast_groups_mask,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============= Endpoint =============
|
||||
|
||||
// ============= Rand Port =============
|
||||
|
||||
/// !!!! need riscv rng
|
||||
|
|
|
|||
|
|
@ -5,12 +5,11 @@ use core::mem::size_of;
|
|||
|
||||
// crate
|
||||
use crate::error::LxError;
|
||||
use crate::net::Endpoint;
|
||||
// use crate::net::Endpoint;
|
||||
|
||||
// smoltcp
|
||||
pub use smoltcp::wire::{IpAddress, Ipv4Address};
|
||||
|
||||
// #
|
||||
use crate::net::*;
|
||||
use kernel_hal::user::{UserInOutPtr, UserOutPtr};
|
||||
// use numeric_enum_macro::numeric_enum;
|
||||
|
|
@ -91,6 +90,58 @@ pub struct SockAddrPlaceholder {
|
|||
pub data: [u8; 14],
|
||||
}
|
||||
|
||||
// ============= Endpoint =============
|
||||
|
||||
use smoltcp::wire::IpEndpoint;
|
||||
|
||||
/// missing documentation
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Endpoint {
|
||||
/// missing documentation
|
||||
Ip(IpEndpoint),
|
||||
/// missing documentation
|
||||
LinkLevel(LinkLevelEndpoint),
|
||||
/// missing documentation
|
||||
Netlink(NetlinkEndpoint),
|
||||
}
|
||||
|
||||
/// missing documentation
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LinkLevelEndpoint {
|
||||
/// missing documentation
|
||||
pub interface_index: usize,
|
||||
}
|
||||
|
||||
impl LinkLevelEndpoint {
|
||||
/// missing documentation
|
||||
pub fn new(ifindex: usize) -> Self {
|
||||
LinkLevelEndpoint {
|
||||
interface_index: ifindex,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// missing documentation
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NetlinkEndpoint {
|
||||
/// missing documentation
|
||||
pub port_id: u32,
|
||||
/// missing documentation
|
||||
pub multicast_groups_mask: u32,
|
||||
}
|
||||
|
||||
impl NetlinkEndpoint {
|
||||
/// missing documentation
|
||||
pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self {
|
||||
NetlinkEndpoint {
|
||||
port_id,
|
||||
multicast_groups_mask,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============= Endpoint =============
|
||||
|
||||
impl From<Endpoint> for SockAddr {
|
||||
fn from(endpoint: Endpoint) -> Self {
|
||||
#[allow(warnings)]
|
||||
|
|
@ -112,32 +163,29 @@ impl From<Endpoint> for SockAddr {
|
|||
},
|
||||
_ => unimplemented!("only ipv4"),
|
||||
}
|
||||
|
||||
// unix socket 暂时 未开启
|
||||
|
||||
// } else if let Endpoint::LinkLevel(link_level) = endpoint {
|
||||
// SockAddr {
|
||||
// addr_ll: SockAddrLl {
|
||||
// sll_family: AddressFamily::Packet.into(),
|
||||
// sll_protocol: 0,
|
||||
// sll_ifindex: link_level.interface_index as u32,
|
||||
// sll_hatype: 0,
|
||||
// sll_pkttype: 0,
|
||||
// sll_halen: 0,
|
||||
// sll_addr: [0; 8],
|
||||
// },
|
||||
// }
|
||||
// } else if let Endpoint::Netlink(netlink) = endpoint {
|
||||
// SockAddr {
|
||||
// addr_nl: SockAddrNl {
|
||||
// nl_family: AddressFamily::Netlink.into(),
|
||||
// nl_pad: 0,
|
||||
// nl_pid: netlink.port_id,
|
||||
// nl_groups: netlink.multicast_groups_mask,
|
||||
// },
|
||||
// }
|
||||
} else if let Endpoint::LinkLevel(link_level) = endpoint {
|
||||
SockAddr {
|
||||
addr_ll: SockAddrLl {
|
||||
sll_family: AddressFamily::Packet.into(),
|
||||
sll_protocol: 0,
|
||||
sll_ifindex: link_level.interface_index as u32,
|
||||
sll_hatype: 0,
|
||||
sll_pkttype: 0,
|
||||
sll_halen: 0,
|
||||
sll_addr: [0; 8],
|
||||
},
|
||||
}
|
||||
} else if let Endpoint::Netlink(netlink) = endpoint {
|
||||
SockAddr {
|
||||
addr_nl: SockAddrNl {
|
||||
nl_family: AddressFamily::Netlink.into(),
|
||||
nl_pad: 0,
|
||||
nl_pid: netlink.port_id,
|
||||
nl_groups: netlink.multicast_groups_mask,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
unimplemented!("only ip");
|
||||
unimplemented!("not match");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ impl TcpSocketState {
|
|||
|
||||
/// missing documentation
|
||||
pub async fn read(&self, data: &mut [u8]) -> (LxResult<usize>, Endpoint) {
|
||||
warn!("tcp read");
|
||||
info!("tcp read");
|
||||
loop {
|
||||
poll_ifaces();
|
||||
let net_sockets = get_sockets();
|
||||
|
|
@ -96,60 +96,9 @@ impl TcpSocketState {
|
|||
}
|
||||
}
|
||||
|
||||
/// missing documentation
|
||||
#[cfg(feature = "e1000")]
|
||||
pub async fn read(&self, data: &mut [u8]) -> (LxResult<usize>, Endpoint) {
|
||||
warn!("tcp read");
|
||||
use core::task::Poll;
|
||||
futures::future::poll_fn(|cx| {
|
||||
self.with(|s| {
|
||||
if s.can_recv() {
|
||||
warn!("can recv ok");
|
||||
if let Ok(size) = s.recv_slice(data) {
|
||||
warn!("--------------Ok size {}", size);
|
||||
if size > 0 {
|
||||
let endpoint = s.remote_endpoint();
|
||||
Poll::Ready((Ok(size), Endpoint::Ip(endpoint)))
|
||||
} else {
|
||||
warn!("wait size > 0");
|
||||
s.register_recv_waker(cx.waker());
|
||||
s.register_send_waker(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
} else {
|
||||
warn!("recv_slice not Ok(size)");
|
||||
Poll::Ready((
|
||||
Err(LxError::ENOTCONN),
|
||||
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
error!("can not recv");
|
||||
s.register_recv_waker(cx.waker());
|
||||
s.register_send_waker(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
})
|
||||
.await
|
||||
// let net_sockets = get_net_sockets();
|
||||
// let mut sockets = net_sockets.lock();
|
||||
// let mut socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
// // if socket.may_recv() {
|
||||
// if let Ok(size) = socket.recv_slice(data) {
|
||||
// let endpoint = socket.remote_endpoint();
|
||||
// return (Ok(size), Endpoint::Ip(endpoint));
|
||||
// } else {
|
||||
// return (
|
||||
// Err(LxError::ENOTCONN),
|
||||
// Endpoint::Ip(IpEndpoint::UNSPECIFIED),
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
/// missing documentation
|
||||
pub fn write(&self, data: &[u8], _sendto_endpoint: Option<Endpoint>) -> SysResult {
|
||||
warn!("tcp write");
|
||||
info!("tcp write");
|
||||
let net_sockets = get_sockets();
|
||||
let mut sockets = net_sockets.lock();
|
||||
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
|
|
@ -241,194 +190,6 @@ impl TcpSocketState {
|
|||
Err(LxError::EINVAL)
|
||||
}
|
||||
}
|
||||
/// missing documentation
|
||||
#[cfg(feature = "e1000")]
|
||||
pub async fn connect(&self, endpoint: Endpoint) -> SysResult {
|
||||
warn!("tcp connect");
|
||||
// if let Endpoint::Ip(ip) = endpoint {
|
||||
// let local_port = get_ephemeral_port();
|
||||
// self.with(|ss| ss.connect(ip, local_port).map_err(|_| LxError::ENOBUFS))?;
|
||||
// // use crate::net::IFaceFuture;
|
||||
// // IFaceFuture { flag: false }.await;
|
||||
// // warn!("no");
|
||||
// // use smoltcp::socket::TcpState;
|
||||
// // let ret = self.with(|ss| match ss.state() {
|
||||
// // TcpState::SynSent => {
|
||||
// // // still connecting
|
||||
// // warn!("SynSent");
|
||||
// // Ok(0)
|
||||
// // }
|
||||
// // TcpState::Established => Ok(0),
|
||||
// // _ => Err(LxError::ECONNREFUSED),
|
||||
// // });
|
||||
|
||||
// // Ok(0)
|
||||
// // socket
|
||||
// // .connect(ip, local_port)
|
||||
// // .map_err(|_| LxError::ENOBUFS)?;
|
||||
|
||||
// // use crate::net::ConnectFuture;
|
||||
// // use smoltcp::socket::SocketRef;
|
||||
// // let c = ConnectFuture {
|
||||
// // socket: SocketRef::into_inner(socket),
|
||||
// // }
|
||||
// // .await;
|
||||
// // drop(c);
|
||||
|
||||
// // use core::future::Future;
|
||||
// // use core::pin::Pin;
|
||||
// // use core::task::Context;
|
||||
// use crate::net::IFaceFuture;
|
||||
// IFaceFuture.await;
|
||||
// // warn!("no");
|
||||
// // IFaceFuture.await;
|
||||
// // warn!("no");
|
||||
// // IFaceFuture.await;
|
||||
// // warn!("no");
|
||||
// // IFaceFuture.await;
|
||||
// // warn!("no");
|
||||
|
||||
// use core::task::Poll;
|
||||
// use smoltcp::socket::TcpState;
|
||||
// let ret = futures::future::poll_fn(|cx| {
|
||||
// self.with(|s| {
|
||||
// // s.connect(ip, local_port).map_err(|_| LxError::ENOBUFS)?;
|
||||
// match s.state() {
|
||||
// TcpState::Closed | TcpState::TimeWait => {
|
||||
// warn!("Closed|TimeWait");
|
||||
// Poll::Ready(Err(LxError::ECONNREFUSED))
|
||||
// }
|
||||
// TcpState::Listen => {
|
||||
// warn!("Listen");
|
||||
// Poll::Ready(Err(LxError::ECONNREFUSED))
|
||||
// }
|
||||
// TcpState::SynSent => {
|
||||
// warn!("SynSent");
|
||||
// s.register_recv_waker(cx.waker());
|
||||
// s.register_send_waker(cx.waker());
|
||||
// // drop(s);
|
||||
// // #[cfg(feature = "e1000")]
|
||||
// // poll_ifaces_e1000();
|
||||
// // IFaceFuture.await
|
||||
// Poll::Pending
|
||||
// }
|
||||
// TcpState::SynReceived => {
|
||||
// warn!("SynReceived");
|
||||
// s.register_recv_waker(cx.waker());
|
||||
// s.register_send_waker(cx.waker());
|
||||
// Poll::Pending
|
||||
// }
|
||||
// TcpState::Established => {
|
||||
// warn!("Established");
|
||||
// // s.register_recv_waker(cx.waker());
|
||||
// // s.register_send_waker(cx.waker());
|
||||
// Poll::Ready(Ok(0))
|
||||
// // Poll::Pending
|
||||
// }
|
||||
// // TcpState::TimeWait => {
|
||||
// // warn!("TimeWait");
|
||||
// // // s.register_recv_waker(cx.waker());
|
||||
// // // s.register_send_waker(cx.waker());
|
||||
// // Poll::Ready(Ok(0))
|
||||
// // // Poll::Pending
|
||||
// // }
|
||||
// TcpState::FinWait1 => {
|
||||
// warn!("------------------------------------FinWait1");
|
||||
// // s.register_recv_waker(cx.waker());
|
||||
// // s.register_send_waker(cx.waker());
|
||||
// Poll::Ready(Ok(0))
|
||||
// // Poll::Pending
|
||||
// }
|
||||
// TcpState::FinWait2 => {
|
||||
// warn!("----------------------------------------FinWait2");
|
||||
// // s.register_recv_waker(cx.waker());
|
||||
// // s.register_send_waker(cx.waker());
|
||||
// Poll::Ready(Ok(0))
|
||||
// // Poll::Pending
|
||||
// }
|
||||
// TcpState::Closing => {
|
||||
// warn!("-------------------------------------------Closing");
|
||||
// // s.register_recv_waker(cx.waker());
|
||||
// // s.register_send_waker(cx.waker());
|
||||
// Poll::Ready(Ok(0))
|
||||
// // Poll::Pending
|
||||
// }
|
||||
// TcpState::LastAck => {
|
||||
// warn!("-------------------------------------------LastAck");
|
||||
// // s.register_recv_waker(cx.waker());
|
||||
// // s.register_send_waker(cx.waker());
|
||||
// Poll::Ready(Ok(0))
|
||||
// // Poll::Pending
|
||||
// }
|
||||
// _ => {
|
||||
// warn!("_");
|
||||
// Poll::Ready(Err(LxError::ECONNREFUSED))
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// .await;
|
||||
// // #[cfg(feature = "e1000")]
|
||||
// // poll_ifaces_e1000();
|
||||
// IFaceFuture.await;
|
||||
// warn!("ret {:?}", ret);
|
||||
// ret
|
||||
// // Ok(0)
|
||||
// } else {
|
||||
// return Err(LxError::EINVAL);
|
||||
// }
|
||||
|
||||
let net_sockets = get_net_sockets();
|
||||
let mut sockets = net_sockets.lock();
|
||||
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
#[allow(warnings)]
|
||||
if let Endpoint::Ip(ip) = endpoint {
|
||||
let local_port = get_ephemeral_port();
|
||||
socket
|
||||
.connect(ip, local_port)
|
||||
.map_err(|_| LxError::ENOBUFS)?;
|
||||
|
||||
// avoid deadlock
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
#[cfg(feature = "e1000")]
|
||||
poll_ifaces_e1000();
|
||||
#[cfg(feature = "loopback")]
|
||||
poll_ifaces_loopback();
|
||||
// wait for connection result
|
||||
loop {
|
||||
warn!("loop");
|
||||
let net_sockets = get_net_sockets();
|
||||
let mut sockets = net_sockets.lock();
|
||||
let socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
use smoltcp::socket::TcpState;
|
||||
match socket.state() {
|
||||
TcpState::SynSent => {
|
||||
// still connecting
|
||||
warn!("SynSent");
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
|
||||
#[cfg(feature = "e1000")]
|
||||
poll_ifaces_e1000();
|
||||
#[cfg(feature = "loopback")]
|
||||
poll_ifaces_loopback();
|
||||
}
|
||||
TcpState::Established => {
|
||||
warn!("estab");
|
||||
break Ok(0);
|
||||
}
|
||||
_ => {
|
||||
break Err(LxError::ECONNREFUSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
return Err(LxError::EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
/// missing documentation
|
||||
fn bind(&mut self, endpoint: Endpoint) -> SysResult {
|
||||
|
|
@ -511,54 +272,6 @@ impl TcpSocketState {
|
|||
drop(sockets);
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "e1000")]
|
||||
async fn accept(&mut self) -> Result<(Arc<Mutex<dyn Socket>>, Endpoint), LxError> {
|
||||
let endpoint = self.local_endpoint.ok_or(LxError::EINVAL)?;
|
||||
|
||||
// let net_sockets = get_net_sockets();
|
||||
// let mut sockets = net_sockets.lock();
|
||||
// let socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
|
||||
// if socket.is_active() {
|
||||
// use crate::net::AcceptFuture;
|
||||
// AcceptFuture {
|
||||
// socket: &mut socket,
|
||||
// }
|
||||
// .await;
|
||||
|
||||
use core::task::Poll;
|
||||
futures::future::poll_fn(|cx| {
|
||||
self.with(|s| {
|
||||
if s.is_active() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
s.register_recv_waker(cx.waker());
|
||||
s.register_send_waker(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
})
|
||||
.await;
|
||||
let remote_endpoint = self.with(|s| s.remote_endpoint());
|
||||
// drop(socket);
|
||||
let new_socket = {
|
||||
let rx_buffer = TcpSocketBuffer::new(vec![0; TCP_RECVBUF]);
|
||||
let tx_buffer = TcpSocketBuffer::new(vec![0; TCP_SENDBUF]);
|
||||
let mut socket = TcpSocket::new(rx_buffer, tx_buffer);
|
||||
socket.listen(endpoint).unwrap();
|
||||
let net_sockets = get_net_sockets();
|
||||
let mut sockets = net_sockets.lock();
|
||||
let new_handle = GlobalSocketHandle(sockets.add(socket));
|
||||
let old_handle = ::core::mem::replace(&mut self.handle, new_handle);
|
||||
Arc::new(Mutex::new(TcpSocketState {
|
||||
// base: KObjectBase::new(),
|
||||
handle: old_handle,
|
||||
local_endpoint: self.local_endpoint,
|
||||
is_listening: false,
|
||||
}))
|
||||
};
|
||||
return Ok((new_socket, Endpoint::Ip(remote_endpoint)));
|
||||
}
|
||||
|
||||
/// missing documentation
|
||||
fn endpoint(&self) -> Option<Endpoint> {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ use alloc::sync::Arc;
|
|||
use alloc::vec;
|
||||
|
||||
// smoltcp
|
||||
|
||||
use smoltcp::socket::UdpPacketMetadata;
|
||||
use smoltcp::socket::UdpSocket;
|
||||
use smoltcp::socket::UdpSocketBuffer;
|
||||
|
|
@ -121,34 +120,6 @@ impl UdpSocketState {
|
|||
drop(sockets);
|
||||
}
|
||||
}
|
||||
/// missing documentation
|
||||
#[cfg(feature = "e1000")]
|
||||
pub async fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) {
|
||||
use core::task::Poll;
|
||||
futures::future::poll_fn(|cx| {
|
||||
self.with(|s| {
|
||||
if s.can_recv() {
|
||||
if let Ok((size, remote_endpoint)) = s.recv_slice(data) {
|
||||
let endpoint = remote_endpoint;
|
||||
warn!("udp read => size : {} , enpoint : {} ", size, endpoint);
|
||||
Poll::Ready((Ok(size), Endpoint::Ip(endpoint)))
|
||||
} else {
|
||||
warn!("recv faill message");
|
||||
Poll::Ready((
|
||||
Err(LxError::ENOTCONN),
|
||||
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
warn!("udp can not recv ,because rx buffer is null");
|
||||
s.register_recv_waker(cx.waker());
|
||||
s.register_send_waker(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// missing documentation
|
||||
pub fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue