forked from rcore-os/zCore
merge from upstream
This commit is contained in:
commit
d53432fab7
|
@ -1,9 +1,16 @@
|
|||
[alias]
|
||||
xtask = "run --package xtask --"
|
||||
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,15 +6,19 @@ on:
|
|||
schedule:
|
||||
- cron: '0 22 * * *' # every day at 22:00 UTC
|
||||
|
||||
env:
|
||||
rust_toolchain: nightly-2022-01-20
|
||||
|
||||
jobs:
|
||||
workspace:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
override: true
|
||||
components: rust-src, rustfmt, clippy
|
||||
|
||||
|
@ -23,16 +27,19 @@ jobs:
|
|||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --all-features
|
||||
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --all-features
|
||||
|
||||
- name: Build docs
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
@ -43,12 +50,14 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- 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
|
||||
|
@ -56,20 +65,19 @@ jobs:
|
|||
args: --target aarch64-unknown-linux-gnu --workspace --exclude linux-syscall --exclude zcore-loader --exclude zcore
|
||||
|
||||
build-user:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-latest]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Pull prebuilt images
|
||||
run: git lfs pull -I prebuilt/zircon/x64/libc.so,prebuilt/zircon/x64/libfdio.so,prebuilt/zircon/x64/libunwind.so,prebuilt/zircon/x64/libzircon.so,prebuilt/zircon/x64/Scrt1.o
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: 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
|
||||
|
||||
|
@ -82,18 +90,19 @@ jobs:
|
|||
os: [ubuntu-latest, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, clippy
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
|
||||
- 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:
|
||||
|
@ -111,20 +120,22 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, clippy
|
||||
|
||||
- uses: actions-rs/install@v0.1
|
||||
with:
|
||||
crate: cargo-binutils
|
||||
version: latest
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
|
||||
- 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 }}
|
||||
|
@ -132,6 +143,7 @@ jobs:
|
|||
- 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,30 +4,25 @@ on:
|
|||
push:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
rust_toolchain: nightly-2022-01-20
|
||||
|
||||
jobs:
|
||||
doc:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
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,33 +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@v3
|
||||
- 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
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
# - uses: Swatinem/rust-cache@v1
|
||||
|
||||
- name: Prepare rootfs
|
||||
run: make rootfs
|
||||
- name: Test
|
||||
run: cargo test --no-fail-fast
|
||||
- name: Run unit test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --no-fail-fast
|
||||
env:
|
||||
CARGO_INCREMENTAL: '0'
|
||||
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
|
||||
RUSTDOCFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
|
||||
|
||||
- name: Cache grcov
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-grcov
|
||||
|
||||
- name: Gather coverage data
|
||||
id: coverage
|
||||
uses: actions-rs/grcov@v0.1
|
||||
|
@ -43,125 +49,131 @@ 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@v3
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
# - uses: Swatinem/rust-cache@v1
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
- name: Run bench test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: bench
|
||||
|
||||
zircon-core-test-libos:
|
||||
name: Zircon Core Test Libos
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- 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
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-01-20
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
# - uses: Swatinem/rust-cache@v1
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip3 install -r tests/requirements.txt
|
||||
- name: Pull prebuilt images
|
||||
run: |
|
||||
git lfs pull -I prebuilt/zircon/x64/core-tests.zbi
|
||||
git lfs pull -I prebuilt/zircon/x64/libzircon-libos.so
|
||||
git lfs pull -I prebuilt/zircon/x64/userboot-libos.so
|
||||
|
||||
- name: Install python dependencies
|
||||
run: .github/scripts/install-deps.sh
|
||||
|
||||
- name: Run fast tests
|
||||
if: github.event_name != 'schedule'
|
||||
run: cd tests && python3 zircon_core_test.py --libos --fast --no-failed
|
||||
|
||||
- name: Run full tests
|
||||
if: github.event_name == 'schedule'
|
||||
run: cd tests && python3 zircon_core_test.py --libos
|
||||
|
||||
linux-libc-test-libos:
|
||||
name: Linux Libc Test Libos
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- 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
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
# - uses: Swatinem/rust-cache@v1
|
||||
|
||||
- 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 libc-test
|
||||
|
||||
- name: Run fast tests
|
||||
if: github.event_name != 'schedule'
|
||||
run: cd tests && python3 linux_libc_test.py --libos --fast
|
||||
|
||||
- name: Run full tests
|
||||
if: github.event_name == 'schedule'
|
||||
run: cd tests && python3 linux_libc_test.py --libos
|
||||
|
||||
zircon-core-test-baremetal:
|
||||
name: Zircon Core Test Baremetal
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x86_64]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
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
|
||||
toolchain: ${{ env.rust_toolchain }}
|
||||
components: rust-src, llvm-tools-preview, rustfmt, clippy
|
||||
# - uses: Swatinem/rust-cache@v1
|
||||
|
||||
- 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: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install ninja-build -y
|
||||
pip3 install -r tests/requirements.txt
|
||||
run: .github/scripts/install-deps.sh ninja-build
|
||||
|
||||
- name: Cache QEMU
|
||||
id: cache-qemu
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: qemu-7.0.0
|
||||
key: qemu-7.0.0-x86_64-riscv64
|
||||
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: |
|
||||
if [ ! -d qemu-7.0.0 ]; then
|
||||
wget https://download.qemu.org/qemu-7.0.0.tar.xz
|
||||
tar -xf qemu-7.0.0.tar.xz
|
||||
cd qemu-7.0.0
|
||||
./configure --target-list=x86_64-softmmu,riscv64-softmmu
|
||||
make -j
|
||||
else
|
||||
cd qemu-7.0.0
|
||||
fi
|
||||
sudo make install
|
||||
qemu-system-${{ matrix.arch }} --version
|
||||
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
|
||||
|
@ -171,54 +183,51 @@ jobs:
|
|||
- 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
|
||||
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
|
||||
# - uses: Swatinem/rust-cache@v1
|
||||
|
||||
- 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
|
||||
id: cache-qemu
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: qemu-7.0.0
|
||||
key: qemu-7.0.0-x86_64-riscv64
|
||||
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: |
|
||||
if [ ! -d qemu-7.0.0 ]; then
|
||||
wget https://download.qemu.org/qemu-7.0.0.tar.xz
|
||||
tar -xf qemu-7.0.0.tar.xz
|
||||
cd qemu-7.0.0
|
||||
./configure --target-list=x86_64-softmmu,riscv64-softmmu
|
||||
make -j
|
||||
else
|
||||
cd qemu-7.0.0
|
||||
fi
|
||||
sudo make install
|
||||
cd qemu-${{ env.qemu_version }} && sudo make install
|
||||
qemu-system-${{ matrix.arch }} --version
|
||||
|
||||
- name: Prepare rootfs
|
||||
run: make test-image ARCH=${{ matrix.arch }}
|
||||
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
|
||||
|
@ -228,49 +237,45 @@ jobs:
|
|||
- 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
|
||||
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
|
||||
# - uses: Swatinem/rust-cache@v1
|
||||
|
||||
- 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
|
||||
id: cache-qemu
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: qemu-7.0.0
|
||||
key: qemu-7.0.0-x86_64-riscv64
|
||||
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: |
|
||||
if [ ! -d qemu-7.0.0 ]; then
|
||||
wget https://download.qemu.org/qemu-7.0.0.tar.xz
|
||||
tar -xf qemu-7.0.0.tar.xz
|
||||
cd qemu-7.0.0
|
||||
./configure --target-list=x86_64-softmmu,riscv64-softmmu
|
||||
make -j
|
||||
else
|
||||
cd qemu-7.0.0
|
||||
fi
|
||||
sudo make install
|
||||
cd qemu-${{ env.qemu_version }} && sudo make install
|
||||
qemu-system-${{ matrix.arch }} --version
|
||||
|
||||
- name: Prepare rootfs
|
||||
run: make image ARCH=${{ matrix.arch }}
|
||||
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 }}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"unistd.h": "c",
|
||||
"time.h": "c"
|
||||
},
|
||||
"rust-analyzer.cargo.target": "riscv64gc-unknown-none-elf",
|
||||
// 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
|
||||
}
|
||||
|
|
29
Makefile
29
Makefile
|
@ -2,7 +2,7 @@
|
|||
|
||||
ARCH ?= x86_64
|
||||
|
||||
.PHONY: help setup rootfs libc-test image test-image check doc clean
|
||||
.PHONY: help setup update rootfs libc-test other-test image check doc clean
|
||||
|
||||
# print top level help
|
||||
help:
|
||||
|
@ -18,18 +18,19 @@ update:
|
|||
|
||||
# put rootfs for linux mode
|
||||
rootfs:
|
||||
cargo rootfs $(ARCH)
|
||||
cargo rootfs --arch $(ARCH)
|
||||
|
||||
# put libc-test into rootfs
|
||||
# put libc tests into rootfs
|
||||
libc-test:
|
||||
cargo libc-test $(ARCH)
|
||||
cargo libc-test --arch $(ARCH)
|
||||
|
||||
# put other tests into rootfs
|
||||
other-test:
|
||||
cargo other-test --arch $(ARCH)
|
||||
|
||||
# build image from rootfs
|
||||
image:
|
||||
cargo image $(ARCH)
|
||||
|
||||
# build image with libc-test
|
||||
test-image: libc-test image
|
||||
cargo image --arch $(ARCH)
|
||||
|
||||
# check code style
|
||||
check:
|
||||
|
@ -44,16 +45,14 @@ aarch64-image: rcore-fs-fuse aarch64-rootfs
|
|||
@rcore-fs-fuse zCore/aarch64.img aarch64_rootfs zip
|
||||
@qemu-img resize -f raw zCore/aarch64.img +5M
|
||||
|
||||
# clean targets
|
||||
clean:
|
||||
cargo clean
|
||||
find zCore -maxdepth 1 -name "*.img" -delete
|
||||
rm -rf rootfs
|
||||
rm -rf riscv-rootfs
|
||||
rm -rf aarch64_rootfs
|
||||
find zCore/target -type f -name "*.zbi" -delete
|
||||
find zCore/target -type f -name "*.elf" -delete
|
||||
rm -rf ignored/target
|
||||
find zCore -maxdepth 1 -name "*.img" -delete
|
||||
|
||||
rt-test:
|
||||
cd rootfs && git clone https://kernel.googlesource.com/pub/scm/linux/kernel/git/clrkwllms/rt-tests --depth 1
|
||||
cd rootfs/rt-tests && make
|
||||
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.
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
1. 先决条件
|
||||
|
||||
目前受关注的开发环境为较新版本的 Ubuntu,建议使用 Ubuntu20.04 或 Ubuntu22.04。
|
||||
本文假设读者使用二者之一。
|
||||
目前已测试的开发环境包括 Ubuntu20.04、Ubuntu22.04 和 Debian11,
|
||||
Ubuntu22.04 不能正确编译 x86_64 的 libc 测试。
|
||||
若不需要烧写到物理硬件,使用 WSL2 或其他虚拟机的操作与真机并无不同之处。
|
||||
|
||||
在开始之前,确保你的计算机上安装了 git 和 rustup。要在虚拟环境开发或测试,需要 QEMU。
|
||||
|
@ -44,6 +44,12 @@
|
|||
make help
|
||||
```
|
||||
|
||||
6. 推到仓库前,现在本机执行测试
|
||||
|
||||
```bash
|
||||
make check # CI/build 的一部分,未来会实现更多快速测试指令
|
||||
```
|
||||
|
||||
## Linux 模式
|
||||
|
||||
zCore 根据向用户提供的系统调用的不同,可分为 zircon 模式和 linux 模式。
|
||||
|
@ -67,6 +73,12 @@ make rootfs ARCH=riscv64
|
|||
make libc-test <ARCH=?>
|
||||
```
|
||||
|
||||
要执行 CI 的其他测试,需要向文件系统中添加相应测试集:
|
||||
|
||||
```bash
|
||||
make other-test <ARCH=?>
|
||||
```
|
||||
|
||||
要以裸机模式启动 zCore,需要构造将放到设备或虚拟环境中的镜像文件:
|
||||
|
||||
```bash
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ 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 {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use lock::Mutex;
|
||||
use riscv::register::sie;
|
||||
use spin::Once;
|
||||
|
||||
use crate::prelude::IrqHandler;
|
||||
use crate::scheme::{IrqScheme, Scheme};
|
||||
|
@ -23,29 +23,29 @@ pub enum ScauseIntCode {
|
|||
|
||||
pub struct Intc {
|
||||
name: String,
|
||||
soft_handler: Once<IrqHandler>,
|
||||
timer_handler: Once<IrqHandler>,
|
||||
ext_handler: Once<IrqHandler>,
|
||||
soft_handler: Mutex<Option<IrqHandler>>,
|
||||
timer_handler: Mutex<Option<IrqHandler>>,
|
||||
ext_handler: Mutex<Option<IrqHandler>>,
|
||||
}
|
||||
|
||||
impl Intc {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name: format!("riscv-intc-cpu{}", INTC_NUM.fetch_add(1, Ordering::Relaxed)),
|
||||
soft_handler: Once::new(),
|
||||
timer_handler: Once::new(),
|
||||
ext_handler: Once::new(),
|
||||
soft_handler: Mutex::new(None),
|
||||
timer_handler: Mutex::new(None),
|
||||
ext_handler: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_handler<F>(&self, cause: usize, op: F) -> DeviceResult
|
||||
where
|
||||
F: FnOnce(&Once<IrqHandler>) -> DeviceResult,
|
||||
F: FnOnce(&mut Option<IrqHandler>) -> DeviceResult,
|
||||
{
|
||||
match cause {
|
||||
S_SOFT => op(&self.soft_handler),
|
||||
S_TIMER => op(&self.timer_handler),
|
||||
S_EXT => op(&self.ext_handler),
|
||||
S_SOFT => op(&mut self.soft_handler.lock()),
|
||||
S_TIMER => op(&mut self.timer_handler.lock()),
|
||||
S_EXT => op(&mut self.ext_handler.lock()),
|
||||
_ => {
|
||||
error!("invalid SCAUSE value {:#x}!", cause);
|
||||
Err(DeviceError::InvalidParam)
|
||||
|
@ -66,9 +66,8 @@ impl Scheme for Intc {
|
|||
}
|
||||
|
||||
fn handle_irq(&self, cause: usize) {
|
||||
trace!("intc handle irq, cause {}", cause);
|
||||
self.with_handler(cause, |opt| {
|
||||
if let Some(h) = opt.get() {
|
||||
if let Some(h) = opt {
|
||||
h();
|
||||
} else {
|
||||
warn!("no registered handler for SCAUSE {}!", cause);
|
||||
|
@ -110,16 +109,23 @@ impl IrqScheme for Intc {
|
|||
|
||||
fn register_handler(&self, cause: usize, handler: IrqHandler) -> DeviceResult {
|
||||
self.with_handler(cause, |opt| {
|
||||
if opt.is_completed() {
|
||||
if opt.is_some() {
|
||||
Err(DeviceError::AlreadyExists)
|
||||
} else {
|
||||
opt.call_once(|| handler);
|
||||
*opt = Some(handler);
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn unregister(&self, _cause: usize) -> DeviceResult {
|
||||
panic!("unregister intc handler unsupported!");
|
||||
fn unregister(&self, cause: usize) -> DeviceResult {
|
||||
self.with_handler(cause, |opt| {
|
||||
if opt.is_some() {
|
||||
*opt = None;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(DeviceError::InvalidParam)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,4 +76,9 @@ pub trait IrqScheme: Scheme {
|
|||
fn init_hart(&self) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// [for x86_64] enable apic timer
|
||||
fn apic_timer_enable(&self) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler", rev = "5
|
|||
[target.'cfg(all(target_os = "none", target_arch = "aarch64"))'.dependencies]
|
||||
executor-origin = { git = "https://github.com/rcore-os/executor.git", package = "executor", rev = "85b9335" }
|
||||
[target.'cfg(target_os = "none")'.dependencies]
|
||||
executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler", rev = "3b04ba4" }
|
||||
naive-timer = "0.2.0"
|
||||
# All mode on x86_64
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
|
@ -72,6 +73,7 @@ x86_64 = "0.14"
|
|||
uefi = "0.11"
|
||||
raw-cpuid = "9.0"
|
||||
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "1069df3" }
|
||||
x2apic = "0.4"
|
||||
|
||||
# Bare-metal mode on riscv64
|
||||
[target.'cfg(all(target_os = "none", target_arch = "riscv64"))'.dependencies]
|
||||
|
|
|
@ -26,7 +26,12 @@ pub(super) fn super_soft() {
|
|||
#[no_mangle]
|
||||
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
||||
let scause = scause::read();
|
||||
trace!("trap happened: {:?}", TrapReason::from(scause));
|
||||
debug!("kernel trap happened: {:?}", TrapReason::from(scause));
|
||||
debug!(
|
||||
"sepc = 0x{:x} pgtoken = 0x{:x}",
|
||||
tf.sepc,
|
||||
crate::vm::current_vmtoken()
|
||||
);
|
||||
match TrapReason::from(scause) {
|
||||
TrapReason::SoftwareBreakpoint => breakpoint(&mut tf.sepc),
|
||||
TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags),
|
||||
|
|
|
@ -33,7 +33,19 @@ pub(super) fn init() -> DeviceResult {
|
|||
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));
|
||||
|
||||
// PCI scan
|
||||
|
|
|
@ -57,7 +57,7 @@ pub fn primary_init() {
|
|||
}
|
||||
|
||||
pub fn timer_init() {
|
||||
// DO NOTHING
|
||||
timer::init();
|
||||
}
|
||||
|
||||
pub fn secondary_init() {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ pub(super) fn super_timer() {
|
|||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
||||
trace!(
|
||||
debug!(
|
||||
"Interrupt: {:#x} @ CPU{}",
|
||||
tf.trap_num,
|
||||
super::cpu::cpu_id()
|
||||
|
|
|
@ -17,7 +17,7 @@ lazy_static! {
|
|||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::hal_fn::timer {
|
||||
fn timer_set_first() {
|
||||
fn timer_enable() {
|
||||
if !FIRST.load(Ordering::Relaxed) {
|
||||
FIRST.store(true, Ordering::Relaxed);
|
||||
super::arch::timer_init();
|
||||
|
|
|
@ -116,7 +116,7 @@ impl TrapReason {
|
|||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn from(trap_num: usize, _elr: usize) -> Self {
|
||||
// TODO: check if is right
|
||||
use crate::{Info, Kind, Source, Syndrome, Fault};
|
||||
use crate::{Fault, Info, Kind, Source, Syndrome};
|
||||
use cortex_a::registers::{ESR_EL1, FAR_EL1};
|
||||
use tock_registers::interfaces::Readable;
|
||||
|
||||
|
@ -129,12 +129,14 @@ impl TrapReason {
|
|||
Kind::Synchronous => match Syndrome::from(esr) {
|
||||
Syndrome::Breakpoint => Self::SoftwareBreakpoint,
|
||||
Syndrome::Svc(_) => Self::Syscall,
|
||||
Syndrome::DataAbort { kind: _, level: _ } => {
|
||||
Self::PageFault(FAR_EL1.get() as _, MMUFlags::READ | MMUFlags::WRITE | MMUFlags::USER)
|
||||
}
|
||||
Syndrome::InstructionAbort { kind: Fault::Permission, level: _ } => {
|
||||
Self::PageFault(FAR_EL1.get() as _, MMUFlags::EXECUTE | MMUFlags::USER)
|
||||
}
|
||||
Syndrome::DataAbort { kind: _, level: _ } => Self::PageFault(
|
||||
FAR_EL1.get() as _,
|
||||
MMUFlags::READ | MMUFlags::WRITE | MMUFlags::USER,
|
||||
),
|
||||
Syndrome::InstructionAbort {
|
||||
kind: Fault::Permission,
|
||||
level: _,
|
||||
} => Self::PageFault(FAR_EL1.get() as _, MMUFlags::EXECUTE | MMUFlags::USER),
|
||||
Syndrome::PCAlignmentFault | Syndrome::SpAlignmentFault => Self::UnalignedAccess,
|
||||
_ => Self::GernelFault(esr as usize),
|
||||
},
|
||||
|
|
|
@ -158,7 +158,7 @@ hal_fn_def! {
|
|||
/// Time and clock functions.
|
||||
pub mod timer {
|
||||
/// Set the first time interrupt
|
||||
pub fn timer_set_first();
|
||||
pub fn timer_enable();
|
||||
|
||||
/// Get current time.
|
||||
/// TODO: use `Instant` as return type.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 1426bea9f3482dec1aa98c31dcc3733a750fb090
|
|
@ -72,7 +72,7 @@ impl Semaphore {
|
|||
inner: Arc<Mutex<SemaphoreInner>>,
|
||||
}
|
||||
|
||||
impl<'a> Future for SemaphoreFuture {
|
||||
impl Future for SemaphoreFuture {
|
||||
type Output = Result<(), LxError>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
|
@ -157,13 +157,13 @@ impl Semaphore {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for SemaphoreGuard<'a> {
|
||||
impl Drop for SemaphoreGuard<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.sem.release();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for SemaphoreGuard<'a> {
|
||||
impl Deref for SemaphoreGuard<'_> {
|
||||
type Target = Semaphore;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
|
|
@ -112,11 +112,11 @@ impl Syscall<'_> {
|
|||
}
|
||||
let sem = &sem_array[num as usize];
|
||||
|
||||
let _result = match op {
|
||||
match op {
|
||||
1 => sem.release(),
|
||||
-1 => sem.acquire().await?,
|
||||
_ => unimplemented!("Semaphore: semop.(Not 1/-1)"),
|
||||
};
|
||||
}
|
||||
sem.set_pid(self.zircon_process().id() as usize);
|
||||
if flags.contains(SemFlags::SEM_UNDO) {
|
||||
self.linux_process().semaphores_add_undo(id, num, op);
|
||||
|
|
|
@ -94,19 +94,27 @@ impl Syscall<'_> {
|
|||
return Err(PagingError::NoMemory);
|
||||
}
|
||||
Err(PagingError::AlreadyMapped) => {
|
||||
panic!("get_vaddr_flags error!!!");
|
||||
panic!("get_vaddr_flags error vaddr(0x{:x})", vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
if is_handle_read_pagefault {
|
||||
if let Err(err) = vmar.handle_page_fault(vaddr, MMUFlags::READ) {
|
||||
panic!("into_out_userptr handle_page_fault: {:?}", err);
|
||||
error!(
|
||||
"into_out_userptr handle_page_fault: {:?} vaddr(0x{:x})",
|
||||
err, vaddr
|
||||
);
|
||||
return Err(PagingError::NotMapped);
|
||||
}
|
||||
}
|
||||
|
||||
if is_handle_write_pagefault {
|
||||
if let Err(err) = vmar.handle_page_fault(vaddr, MMUFlags::WRITE) {
|
||||
panic!("into_out_userptr handle_page_fault: {:?}", err);
|
||||
error!(
|
||||
"into_out_userptr handle_page_fault: {:?} vaddr(0x{:x})",
|
||||
err, vaddr
|
||||
);
|
||||
return Err(PagingError::NotMapped);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -106,7 +106,7 @@ impl Syscall<'_> {
|
|||
Err(_e) => return Err(LxError::EACCES),
|
||||
}
|
||||
};
|
||||
warn!(
|
||||
debug!(
|
||||
"Futex uaddr: {:#x}, op: {:x}, val: {}, timeout_ptr: {:x?}, val2: {}",
|
||||
uaddr,
|
||||
op.bits(),
|
||||
|
|
|
@ -8,6 +8,7 @@ use bitflags::bitflags;
|
|||
use kernel_hal::context::UserContextField;
|
||||
use linux_object::thread::{CurrentThreadExt, RobustList, ThreadExt};
|
||||
use linux_object::{fs::INodeExt, loader::LinuxElfLoader};
|
||||
use zircon_object::vm::USER_STACK_PAGES;
|
||||
|
||||
/// Syscalls for process.
|
||||
///
|
||||
|
@ -285,7 +286,7 @@ impl Syscall<'_> {
|
|||
|
||||
let (entry, sp) = LinuxElfLoader {
|
||||
syscall_entry: self.syscall_entry,
|
||||
stack_pages: 8,
|
||||
stack_pages: USER_STACK_PAGES,
|
||||
root_inode: proc.root_inode().clone(),
|
||||
}
|
||||
.load(&vmar, &data, args, envs, path)?;
|
||||
|
|
|
@ -13,7 +13,7 @@ async fn main() {
|
|||
}
|
||||
|
||||
let envs = vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin".into()];
|
||||
let rootfs_path = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join("../rootfs");
|
||||
let rootfs_path = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join("../rootfs/x86_64");
|
||||
let hostfs = rcore_fs_hostfs::HostFS::new(rootfs_path);
|
||||
|
||||
let proc = zcore_loader::linux::run(args[1..].to_vec(), envs, hostfs);
|
||||
|
|
|
@ -11,7 +11,7 @@ use linux_object::fs::{vfs::FileSystem, INodeExt};
|
|||
use linux_object::thread::{CurrentThreadExt, ThreadExt};
|
||||
use linux_object::{loader::LinuxElfLoader, process::ProcessExt};
|
||||
use zircon_object::task::{CurrentThread, Job, Process, Thread, ThreadState};
|
||||
use zircon_object::{object::KernelObject, ZxError, ZxResult};
|
||||
use zircon_object::{object::KernelObject, vm::USER_STACK_PAGES, ZxError, ZxResult};
|
||||
|
||||
/// Create and run main Linux process
|
||||
pub fn run(args: Vec<String>, envs: Vec<String>, rootfs: Arc<dyn FileSystem>) -> Arc<Process> {
|
||||
|
@ -22,7 +22,7 @@ pub fn run(args: Vec<String>, envs: Vec<String>, rootfs: Arc<dyn FileSystem>) ->
|
|||
let thread = Thread::create_linux(&proc).unwrap();
|
||||
let loader = LinuxElfLoader {
|
||||
syscall_entry: kernel_hal::context::syscall_entry as usize,
|
||||
stack_pages: 8,
|
||||
stack_pages: USER_STACK_PAGES,
|
||||
root_inode: rootfs.root_inode(),
|
||||
};
|
||||
|
||||
|
@ -71,11 +71,20 @@ async fn run_user(thread: CurrentThread) {
|
|||
}
|
||||
|
||||
// run
|
||||
trace!("go to user: tid = {} ctx = {:#x?}", thread.id(), ctx);
|
||||
kernel_hal::interrupt::intr_off(); // trapframe can't be interrupted
|
||||
debug!(
|
||||
"go to user: tid = {} pc = {:x}",
|
||||
thread.id(),
|
||||
ctx.get_field(UserContextField::InstrPointer)
|
||||
);
|
||||
// trace!("ctx = {:#x?}", ctx);
|
||||
ctx.enter_uspace();
|
||||
kernel_hal::interrupt::intr_on();
|
||||
trace!("back from user: tid = {} ctx = {:#x?}", thread.id(), ctx);
|
||||
debug!(
|
||||
"back from user: tid = {} pc = {:x} trap reason = {:?}",
|
||||
thread.id(),
|
||||
ctx.get_field(UserContextField::InstrPointer),
|
||||
ctx.trap_reason(),
|
||||
);
|
||||
// trace!("ctx = {:#x?}", ctx);
|
||||
// handle trap/interrupt/syscall
|
||||
if let Err(err) = handle_user_trap(&thread, ctx).await {
|
||||
thread.exit_linux(err as i32);
|
||||
|
@ -128,7 +137,6 @@ async fn handle_signal(
|
|||
} else {
|
||||
(*ctx).setup_uspace(action.handler, sp, &[signal as usize, 0, 0]);
|
||||
}
|
||||
(*ctx).enter_uspace();
|
||||
}
|
||||
ctx
|
||||
}
|
||||
|
@ -143,6 +151,16 @@ pub unsafe fn push_stack<T>(stack_top: usize, val: T) -> usize {
|
|||
stack_top as usize
|
||||
}
|
||||
|
||||
use kernel_hal::interrupt::{intr_off, intr_on};
|
||||
|
||||
macro_rules! run_with_irq_enable {
|
||||
($($statements:stmt)*) => {
|
||||
intr_on();
|
||||
$($statements)*
|
||||
intr_off();
|
||||
};
|
||||
}
|
||||
|
||||
async fn handle_user_trap(thread: &CurrentThread, mut ctx: Box<UserContext>) -> ZxResult {
|
||||
let reason = ctx.trap_reason();
|
||||
if let TrapReason::Syscall = reason {
|
||||
|
@ -156,7 +174,9 @@ async fn handle_user_trap(thread: &CurrentThread, mut ctx: Box<UserContext>) ->
|
|||
syscall_entry: kernel_hal::context::syscall_entry as usize,
|
||||
};
|
||||
trace!("Syscall : {} {:x?}", num as u32, args);
|
||||
let ret = syscall.syscall(num as u32, args).await as usize;
|
||||
run_with_irq_enable! {
|
||||
let ret = syscall.syscall(num as u32, args).await as usize
|
||||
}
|
||||
thread.with_context(|ctx| ctx.set_field(UserContextField::ReturnValue, ret))?;
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -166,7 +186,9 @@ async fn handle_user_trap(thread: &CurrentThread, mut ctx: Box<UserContext>) ->
|
|||
let pid = thread.proc().id();
|
||||
match reason {
|
||||
TrapReason::Interrupt(vector) => {
|
||||
kernel_hal::interrupt::handle_irq(vector);
|
||||
run_with_irq_enable! {
|
||||
kernel_hal::interrupt::handle_irq(vector)
|
||||
}
|
||||
#[cfg(not(feature = "libos"))]
|
||||
if vector == kernel_hal::context::TIMER_INTERRUPT_VEC {
|
||||
kernel_hal::thread::yield_now().await;
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
use rcore_fs_hostfs::HostFS;
|
||||
use std::fs;
|
||||
|
||||
const LIBOS_ROOTFS: &str = "../rootfs/x86_64";
|
||||
|
||||
/// test with cmd line
|
||||
async fn test(cmdline: &str) -> i64 {
|
||||
kernel_hal::init();
|
||||
|
||||
let args: Vec<String> = cmdline.split(' ').map(|s| s.into()).collect();
|
||||
let envs = vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()]; // TODO
|
||||
let hostfs = HostFS::new("../rootfs");
|
||||
let hostfs = HostFS::new(LIBOS_ROOTFS);
|
||||
let proc = zcore_loader::linux::run(args, envs, hostfs);
|
||||
proc.wait_for_exit().await
|
||||
}
|
||||
|
@ -45,24 +47,26 @@ async fn test_dir() {
|
|||
|
||||
#[async_std::test]
|
||||
async fn test_create_remove_file() {
|
||||
let test_file = format!("{LIBOS_ROOTFS}/testfile");
|
||||
test("/bin/busybox rm testfile").await; // can't remove
|
||||
fs::read("../rootfs/testfile").unwrap_err();
|
||||
fs::read(&test_file).unwrap_err();
|
||||
test("/bin/busybox touch testfile").await;
|
||||
fs::read("../rootfs/testfile").unwrap();
|
||||
fs::read(&test_file).unwrap();
|
||||
test("/bin/busybox touch testfile").await;
|
||||
fs::read("../rootfs/testfile").unwrap();
|
||||
fs::read(&test_file).unwrap();
|
||||
test("/bin/busybox rm testfile").await;
|
||||
fs::read("../rootfs/testfile").unwrap_err();
|
||||
fs::read(&test_file).unwrap_err();
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_create_remove_dir() {
|
||||
let test = format!("{LIBOS_ROOTFS}/test");
|
||||
test("/bin/busybox rmdir test").await; // can't remove
|
||||
fs::read_dir("../rootfs/test").unwrap_err();
|
||||
fs::read_dir(&test).unwrap_err();
|
||||
test("/bin/busybox mkdir test").await;
|
||||
fs::read_dir("../rootfs/test").unwrap();
|
||||
fs::read_dir(&test).unwrap();
|
||||
test("/bin/busybox rmdir test").await;
|
||||
fs::read_dir("../rootfs/test").unwrap_err();
|
||||
fs::read_dir(&test).unwrap_err();
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
|
@ -73,22 +77,24 @@ async fn test_readfile() {
|
|||
|
||||
#[async_std::test]
|
||||
async fn test_cp_mv() {
|
||||
let hostname = format!("{LIBOS_ROOTFS}/etc/hostname.bak");
|
||||
test("/bin/busybox cp /etc/hostnama /etc/hostname.bak").await; // can't move
|
||||
fs::read("../rootfs/etc/hostname.bak").unwrap_err();
|
||||
fs::read(&hostname).unwrap_err();
|
||||
test("/bin/busybox cp /etc/hostname /etc/hostname.bak").await;
|
||||
fs::read("../rootfs/etc/hostname.bak").unwrap();
|
||||
fs::read(&hostname).unwrap();
|
||||
test("/bin/busybox mv /etc/hostname.bak /etc/hostname.mv").await;
|
||||
fs::read("../rootfs/etc/hostname.bak").unwrap_err();
|
||||
fs::read(&hostname).unwrap_err();
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_link() {
|
||||
let hostname = format!("{LIBOS_ROOTFS}/etc/hostname.ln");
|
||||
test("/bin/busybox ln /etc/hostnama /etc/hostname.ln").await; // can't ln
|
||||
fs::read("../rootfs/etc/hostname.ln").unwrap_err();
|
||||
fs::read(&hostname).unwrap_err();
|
||||
test("/bin/busybox ln /etc/hostname /etc/hostname.ln").await;
|
||||
fs::read("../rootfs/etc/hostname.ln").unwrap();
|
||||
fs::read(&hostname).unwrap();
|
||||
test("/bin/busybox unlink /etc/hostname.ln").await;
|
||||
fs::read("../rootfs/etc/hostname.ln").unwrap_err();
|
||||
fs::read(&hostname).unwrap_err();
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
|
@ -109,7 +115,7 @@ async fn test_sleep() {
|
|||
#[async_std::test]
|
||||
async fn test_truncate() {
|
||||
assert_eq!(test("/bin/busybox truncate -s 12 testtruncate").await, 0);
|
||||
fs::read("../rootfs/testtruncate").unwrap();
|
||||
fs::read(format!("{LIBOS_ROOTFS}/testtruncate")).unwrap();
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
|
|
BIN
prebuilt/linux/README.md (Stored with Git LFS)
BIN
prebuilt/linux/README.md (Stored with Git LFS)
Binary file not shown.
BIN
prebuilt/linux/libc-libos.so (Stored with Git LFS)
BIN
prebuilt/linux/libc-libos.so (Stored with Git LFS)
Binary file not shown.
BIN
prebuilt/linux/riscv64/busybox (Stored with Git LFS)
BIN
prebuilt/linux/riscv64/busybox (Stored with Git LFS)
Binary file not shown.
BIN
prebuilt/linux/riscv64/hello (Stored with Git LFS)
BIN
prebuilt/linux/riscv64/hello (Stored with Git LFS)
Binary file not shown.
|
@ -0,0 +1,54 @@
|
|||
# 更新公告
|
||||
|
||||
最新的更新将出现在最上方。
|
||||
|
||||
## 20220521(YdrMaster)
|
||||
|
||||
- 适用于 libos 的 musl libc so 文件不再通过 git lfs 获取;
|
||||
|
||||
## 20220513(YdrMaster)
|
||||
|
||||
- 选择架构现在是一个参数而不是子命令,例如 `cargo rootfs --arch x86_64`;
|
||||
- 增加 `asm` 指令将指定参数编译的内核反汇编到文件;
|
||||
- 增加 `qemu` 指令在 QEMU 中启动 zCore(目前仅支持 RiscV64+Linux),可配置 SMP,可配置连接 gdb;
|
||||
- 增加 `gdb` 指令启动 gdb 并连接指定端口(目前仅支持 RiscV64)。
|
||||
|
||||
## 20220512(YdrMaster)
|
||||
|
||||
`cargo check-style` 现在会依 CI/build 的方式工作。
|
||||
|
||||
## 20220511(YdrMaster)
|
||||
|
||||
### 目录结构定义
|
||||
|
||||
- 现在用于 linux 模式的 rootfs 统一放在 `rootfs/{arch}` 目录,未来新增 aarch64 或更多架构也将放在这个目录;
|
||||
- 不再将构建过程产生的东西放在 `prebuilt` 目录。现在 `prebuilt` 目录完全来自 `git lfs pull`;
|
||||
- 下载的源文件放在 `ignored/origin/{arch}`,`make clean` 时不会清除这些文件;
|
||||
- 解压或构建过程产生的其他文件放在 `ignored/target/{arch}`,`make clean` 会清除这些文件;
|
||||
- `libc-test` 现在是一个子模块,不再需要单独 `git clone`;
|
||||
|
||||
### 使用步骤
|
||||
|
||||
- 现在 `cargo rootfs {arch}` 将清空已有 `rootfs/{arch}`,然后产生供 zCore 以 linux 模式启动的最小文件系统——只有 `/bin/busybox` 和 `lib/lib/ld-musl-{arch}.so.1` 两个文件,以及一些指向 busybox 的符号链接;
|
||||
- `cargo libc-test {arch}` 命令将向 `rootfs/{arch}` 放入 libc 测试的测例文件,在必要时下载交叉编译工具链;
|
||||
- 增加 `cargo other-test {arch}` 命令,向 `rootfs/{arch}` 放入其他测试的测例文件;
|
||||
- `cargo image {arch}` 命令将 `rootfs/{arch}` 打包成 `zCore/{arch}.img` 文件,过程中不关心 `rootfs/{arch}` 的内容。因此如需要向文件系统加入文件,在 `image` 之前放入 `rootfs/{arch}` 即可;
|
||||
- `libc-test`、`other-test`、`image` 都不需要先 `rootfs`,如果 `rootfs/{arch}` 目录不存在,将自动创建;
|
||||
|
||||
### 实现变更
|
||||
|
||||
- 使用 `std::os::unix::fs::symlink` 建立符号链接,不再依赖 `ln` 应用程序;
|
||||
|
||||
## 20220506(YdrMaster)
|
||||
|
||||
顶层的 Makefile 已经尽量迁移到 rust,并在子项目 README.md 中更新了子命令说明。
|
||||
|
||||
计划提起一次 PR。
|
||||
|
||||
## 20220504(YdrMaster)
|
||||
|
||||
初步的计划是先尽量将 Makefile 转化为类型安全且更有可能工程化结构化的 Rust xtask。
|
||||
尤其是要将 zCore 目录内外的两个 Makefile 合并。
|
||||
|
||||
目前已经架空了外面 Makefile 的 rootfs 指令,这个指令是用于将加载到内存的最小系统的。
|
||||
外面的 Makefile 还剩打包镜像、启动某些测试集的功能,但目前命令之间不正交,还需要进一步梳理。
|
|
@ -10,13 +10,14 @@ build = "build.rs"
|
|||
|
||||
[dependencies]
|
||||
clap = { version = "3.1", features = ["derive"] }
|
||||
clap-verbosity-flag = "1.0"
|
||||
dircpy = "0.3"
|
||||
rand = "0.8"
|
||||
shadow-rs = "0.11"
|
||||
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-fuse = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
|
||||
|
||||
[build-dependencies]
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
shadow-rs = "0.11"
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.build-dependencies]
|
||||
shadow-rs = "0.11"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# zCore tasks
|
||||
|
||||
[更新公告](CHANGLOG.md)
|
||||
|
||||
## 使用说明
|
||||
|
||||
使用 `cargo xtask help` 将打印出命令说明。对主要子命令的简要说明如下:
|
||||
|
@ -8,11 +10,15 @@
|
|||
2. `setup`: 拉取预编译文件和子项目,补全仓库;
|
||||
3. `update-all`: 更新工具链、依赖和子项目;
|
||||
4. `check-style`: 编译前检查;
|
||||
5. `rootfs <arch>`: 创建架构相关的 linux 启动文件系统;
|
||||
6. `libc-test <arch>`: 向启动文件系统加入 libc 测试;
|
||||
7. `image <arch>`: 打包指定架构的系统镜像;
|
||||
5. `rootfs --arch <arch>`: 创建架构相关的 linux 启动文件系统;
|
||||
6. `libc-test --arch <arch>`: 向启动文件系统加入 libc 测试;
|
||||
7. `other-test --arch <arch>`: 向启动文件系统加入其他测试;
|
||||
8. `image --arch <arch>`: 打包指定架构的系统镜像;
|
||||
9. `asm --arch <arch> --output <file name>`: 构建指定架构内核,并反汇编到文件;
|
||||
10. `qemu --arch <arch>`: 启动指定架构的 Qemu 运行内核;
|
||||
11. `gdb --arch <arch> --port <port>`: 启动指定架构的 GDB 并连接到端口;
|
||||
|
||||
其中 5、6、7 必须顺序执行,后者依赖前者的结果;
|
||||
其中 6、7、8 执行时若 5 的结果不存在,将自动递归执行 5;
|
||||
|
||||
## 项目愿景
|
||||
|
||||
|
@ -28,23 +34,7 @@
|
|||
- [x] 更新测例和测试系统
|
||||
- [ ] 支持 zCore 使用
|
||||
- [ ] 以 LibOS 形式启动 zCore
|
||||
- [ ] 在 Qemu 环境中启动 zCore
|
||||
- [x] 在 Qemu 环境中启动 zCore
|
||||
- [x] 打包可烧写到其他存储介质的 zCore 镜像
|
||||
- [ ] 启动与 Qemu 关联的 GDB 以支持内核调试
|
||||
- [x] 启动与 Qemu 关联的 GDB 以支持内核调试
|
||||
- [ ] 自动化测试:实现与 CI 的逻辑一致性
|
||||
|
||||
## 进度日志
|
||||
|
||||
- 2022/05/06
|
||||
|
||||
顶层的 Makefile 已经尽量迁移到 rust,并在子项目 README.md 中更新了子命令说明。
|
||||
|
||||
计划提起一次 PR。
|
||||
|
||||
- 2022/05/04
|
||||
|
||||
初步的计划是先尽量将 Makefile 转化为类型安全且更有可能工程化结构化的 Rust xtask。
|
||||
尤其是要将 zCore 目录内外的两个 Makefile 合并。
|
||||
|
||||
目前已经架空了外面 Makefile 的 rootfs 指令,这个指令是用于将加载到内存的最小系统的。
|
||||
外面的 Makefile 还剩打包镜像、启动某些测试集的功能,但目前命令之间不正交,还需要进一步梳理。
|
||||
|
|
|
@ -1,298 +1,247 @@
|
|||
use crate::{
|
||||
dir,
|
||||
download::{git_clone, wget},
|
||||
CommandExt, ALPINE_ROOTFS_VERSION, ALPINE_WEBSITE,
|
||||
//! 平台相关的操作。
|
||||
|
||||
use crate::{
|
||||
command::{dir, download::wget, CommandExt, Ext, Make, Qemu, Tar},
|
||||
Arch, ALPINE_ROOTFS_VERSION, ALPINE_WEBSITE,
|
||||
};
|
||||
use dircpy::copy_dir;
|
||||
use std::{
|
||||
ffi::{OsStr, OsString},
|
||||
fs,
|
||||
io::Write,
|
||||
os::unix,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
#[derive(Args)]
|
||||
pub(super) struct Arch {
|
||||
#[clap(subcommand)]
|
||||
command: ArchCommands,
|
||||
pub(crate) struct ArchArg {
|
||||
/// Build architecture, `riscv64` or `x86_64`.
|
||||
#[clap(short, long)]
|
||||
pub arch: Arch,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum ArchCommands {
|
||||
#[clap(name = "riscv64")]
|
||||
Riscv64,
|
||||
#[clap(name = "x86_64")]
|
||||
X86_64,
|
||||
}
|
||||
impl ArchArg {
|
||||
const RISCV64: Self = Self {
|
||||
arch: Arch::Riscv64,
|
||||
};
|
||||
const X86_64: Self = Self { arch: Arch::X86_64 };
|
||||
|
||||
impl Arch {
|
||||
/// 构造启动内存文件系统 rootfs。
|
||||
///
|
||||
/// 将在文件系统中放置必要的库文件,并下载用于交叉编译的工具链。
|
||||
pub fn rootfs(&self, clear: bool) {
|
||||
self.wget_alpine();
|
||||
match self.command {
|
||||
ArchCommands::Riscv64 => {
|
||||
const DIR: &str = "riscv_rootfs";
|
||||
const ARCH: &str = "riscv64";
|
||||
|
||||
let dir = Path::new(DIR);
|
||||
if dir.is_dir() && !clear {
|
||||
return;
|
||||
}
|
||||
dir::clear(dir).unwrap();
|
||||
let tar = dir::detect(&format!("prebuilt/linux/{ARCH}"), "minirootfs").unwrap();
|
||||
Tar::xf(&tar, Some(DIR))
|
||||
.args(&["--strip-components", "1"])
|
||||
.join();
|
||||
Command::new("ln")
|
||||
.args(&["-s", "busybox", "riscv_rootfs/bin/ls"])
|
||||
.status()
|
||||
.unwrap()
|
||||
.exit_ok()
|
||||
.expect("FAILED: ln -s busybox riscv_rootfs/bin/ls");
|
||||
}
|
||||
ArchCommands::X86_64 => {
|
||||
const DIR: &str = "rootfs";
|
||||
const ARCH: &str = "x86_64";
|
||||
|
||||
let dir = Path::new(DIR);
|
||||
if dir.is_dir() && !clear {
|
||||
return;
|
||||
}
|
||||
dir::clear(DIR).unwrap();
|
||||
let tar = dir::detect(&format!("prebuilt/linux/{ARCH}"), "minirootfs").unwrap();
|
||||
Tar::xf(&tar, Some(DIR)).join();
|
||||
// libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore
|
||||
fs::copy(
|
||||
"prebuilt/linux/libc-libos.so",
|
||||
format!("{DIR}/lib/ld-musl-{ARCH}.so.1"),
|
||||
)
|
||||
.unwrap();
|
||||
{
|
||||
const TEST_DIR: &str = "linux-syscall/test";
|
||||
const DEST_DIR: &str = "rootfs/bin/";
|
||||
// for linux syscall tests
|
||||
fs::read_dir(TEST_DIR)
|
||||
.unwrap()
|
||||
.filter_map(|res| res.ok())
|
||||
.map(|entry| entry.path())
|
||||
.filter(|path| path.extension().map_or(false, |ext| ext == OsStr::new("c")))
|
||||
.for_each(|c| {
|
||||
let o = format!(
|
||||
"{DEST_DIR}/{}",
|
||||
c.file_prefix().and_then(|s| s.to_str()).unwrap()
|
||||
);
|
||||
Command::new("gcc")
|
||||
.arg(&c)
|
||||
.args(&["-o", &o])
|
||||
.arg("-Wl,--dynamic-linker=/lib/ld-musl-x86_64.so.1")
|
||||
.status()
|
||||
.unwrap()
|
||||
.exit_ok()
|
||||
.expect("FAILED: gcc {c:?}");
|
||||
});
|
||||
}
|
||||
}
|
||||
/// 对于 x86_64,这个文件系统可用于 libos 启动。
|
||||
/// 若设置 `clear`,将清除已存在的目录。
|
||||
pub fn make_rootfs(&self, clear: bool) {
|
||||
// 若已存在且不需要清空,可以直接退出
|
||||
let dir = self.rootfs();
|
||||
if dir.is_dir() && !clear {
|
||||
return;
|
||||
}
|
||||
// 下载压缩文件并解压
|
||||
let src = self.prebuild_rootfs();
|
||||
// 创建目标目录
|
||||
dir::clear(&dir).unwrap();
|
||||
fs::create_dir(dir.join("bin")).unwrap();
|
||||
fs::create_dir(dir.join("lib")).unwrap();
|
||||
// 拷贝 busybox
|
||||
fs::copy(src.join("bin/busybox"), dir.join("bin/busybox")).unwrap();
|
||||
// 拷贝 libc.so
|
||||
let libc_so = format!("lib/ld-musl-{arch}.so.1", arch = self.arch.as_str());
|
||||
let so = match self.arch {
|
||||
Arch::Riscv64 => src.join(&libc_so),
|
||||
Arch::X86_64 => libos_libc_so(),
|
||||
};
|
||||
fs::copy(so, dir.join(libc_so)).unwrap();
|
||||
// 为常用功能建立符号链接
|
||||
const SH: &[&str] = &[
|
||||
"cat", "cp", "echo", "false", "grep", "gzip", "kill", "ln", "ls", "mkdir", "mv",
|
||||
"pidof", "ping", "ping6", "printenv", "ps", "pwd", "rm", "rmdir", "sh", "sleep",
|
||||
"stat", "tar", "touch", "true", "uname", "usleep", "watch",
|
||||
];
|
||||
let bin = dir.join("bin");
|
||||
for sh in SH {
|
||||
unix::fs::symlink("busybox", bin.join(sh)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// 将 libc-test 放入 rootfs。
|
||||
pub fn libc_test(&self) {
|
||||
self.rootfs(false);
|
||||
git_clone(
|
||||
"https://github.com/rcore-os/libc-test.git",
|
||||
"ignored/libc-test",
|
||||
);
|
||||
match self.command {
|
||||
ArchCommands::Riscv64 => {
|
||||
const DIR: &str = "riscv_rootfs/libc-test";
|
||||
const PRE: &str = "riscv_rootfs/libc-test-prebuild";
|
||||
|
||||
fs::rename(DIR, PRE).unwrap();
|
||||
copy_dir("ignored/libc-test", DIR).unwrap();
|
||||
fs::copy(format!("{DIR}/config.mak.def"), format!("{DIR}/config.mak")).unwrap();
|
||||
pub fn put_libc_test(&self) {
|
||||
// 递归 rootfs
|
||||
self.make_rootfs(false);
|
||||
// 拷贝仓库
|
||||
let dir = self.libc_test();
|
||||
dir::rm(&dir).unwrap();
|
||||
copy_dir("libc-test", &dir).unwrap();
|
||||
// 编译
|
||||
fs::copy(dir.join("config.mak.def"), dir.join("config.mak")).unwrap();
|
||||
match self.arch {
|
||||
Arch::Riscv64 => {
|
||||
Make::new(None)
|
||||
.env("ARCH", "riscv64")
|
||||
.env("ARCH", self.arch.as_str())
|
||||
.env("CROSS_COMPILE", "riscv64-linux-musl-")
|
||||
.env("PATH", riscv64_linux_musl_cross())
|
||||
.current_dir(DIR)
|
||||
.join();
|
||||
.current_dir(&dir)
|
||||
.invoke();
|
||||
fs::copy(
|
||||
format!("{PRE}/functional/tls_align-static.exe"),
|
||||
format!("{DIR}/src/functional/tls_align-static.exe"),
|
||||
self.target()
|
||||
.join("rootfs/libc-test/functional/tls_align-static.exe"),
|
||||
dir.join("src/functional/tls_align-static.exe"),
|
||||
)
|
||||
.unwrap();
|
||||
dir::rm(PRE).unwrap();
|
||||
}
|
||||
ArchCommands::X86_64 => {
|
||||
const DIR: &str = "rootfs/libc-test";
|
||||
|
||||
dir::rm(DIR).unwrap();
|
||||
copy_dir("ignored/libc-test", DIR).unwrap();
|
||||
fs::copy(format!("{DIR}/config.mak.def"), format!("{DIR}/config.mak")).unwrap();
|
||||
Arch::X86_64 => {
|
||||
fs::OpenOptions::new()
|
||||
.append(true)
|
||||
.open(format!("{DIR}/config.mak"))
|
||||
.open(dir.join("config.mak"))
|
||||
.unwrap()
|
||||
.write_all(b"CC := musl-gcc\nAR := ar\nRANLIB := ranlib")
|
||||
.unwrap();
|
||||
Make::new(None).current_dir(DIR).join();
|
||||
Make::new(None).current_dir(dir).invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 将其他测试放入 rootfs。
|
||||
pub fn put_other_test(&self) {
|
||||
// 递归 rootfs
|
||||
self.make_rootfs(false);
|
||||
let rootfs = self.rootfs();
|
||||
match self.arch {
|
||||
Arch::Riscv64 => {
|
||||
let target = self.target();
|
||||
copy_dir(target.join("rootfs/oscomp"), rootfs.join("oscomp")).unwrap();
|
||||
}
|
||||
Arch::X86_64 => {
|
||||
let bin = rootfs.join("bin");
|
||||
fs::read_dir("linux-syscall/test")
|
||||
.unwrap()
|
||||
.filter_map(|res| res.ok())
|
||||
.map(|entry| entry.path())
|
||||
.filter(|path| path.extension().map_or(false, |ext| ext == OsStr::new("c")))
|
||||
.for_each(|c| {
|
||||
Ext::new("gcc")
|
||||
.arg(&c)
|
||||
.arg("-o")
|
||||
.arg(bin.join(c.file_prefix().unwrap()))
|
||||
.arg("-Wl,--dynamic-linker=/lib/ld-musl-x86_64.so.1")
|
||||
.invoke();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 生成镜像。
|
||||
pub fn image(&self) {
|
||||
self.rootfs(false);
|
||||
let image = match self.command {
|
||||
ArchCommands::Riscv64 => {
|
||||
const ARCH: &str = "riscv64";
|
||||
|
||||
let image = format!("zCore/{ARCH}.img");
|
||||
fuse("riscv_rootfs", &image);
|
||||
// 递归 rootfs
|
||||
self.make_rootfs(false);
|
||||
let arch_str = self.arch.as_str();
|
||||
let image = match self.arch {
|
||||
Arch::Riscv64 => {
|
||||
let rootfs = format!("rootfs/{arch_str}");
|
||||
let image = format!("zCore/{arch_str}.img");
|
||||
fuse(rootfs, &image);
|
||||
image
|
||||
}
|
||||
ArchCommands::X86_64 => {
|
||||
const ARCH: &str = "x86_64";
|
||||
const TMP_ROOTFS: &str = "/tmp/rootfs";
|
||||
const ROOTFS_LIB: &str = "rootfs/lib";
|
||||
Arch::X86_64 => {
|
||||
let rootfs = self.rootfs();
|
||||
let to = rootfs.join("lib/ld-musl-x86_64.so.1");
|
||||
fs::copy(self.target().join("rootfs/lib/ld-musl-x86_64.so.1"), &to).unwrap();
|
||||
|
||||
// ld-musl-x86_64.so.1 替换为适用 bare-matel 的版本
|
||||
dir::clear(TMP_ROOTFS).unwrap();
|
||||
let tar = dir::detect(&format!("prebuilt/linux/{ARCH}"), "minirootfs").unwrap();
|
||||
Tar::xf(&tar, Some(TMP_ROOTFS)).join();
|
||||
dir::clear(ROOTFS_LIB).unwrap();
|
||||
fs::copy(
|
||||
format!("{TMP_ROOTFS}/lib/ld-musl-x86_64.so.1"),
|
||||
format!("{ROOTFS_LIB}/ld-musl-x86_64.so.1"),
|
||||
)
|
||||
.unwrap();
|
||||
let image = format!("zCore/{arch_str}.img");
|
||||
fuse(rootfs, &image);
|
||||
|
||||
fs::copy(libos_libc_so(), to).unwrap();
|
||||
|
||||
let image = format!("zCore/{ARCH}.img");
|
||||
fuse("rootfs", &image);
|
||||
fs::copy(
|
||||
"prebuilt/linux/libc-libos.so",
|
||||
format!("{ROOTFS_LIB}/ld-musl-x86_64.so.1"),
|
||||
)
|
||||
.unwrap();
|
||||
image
|
||||
}
|
||||
};
|
||||
Command::new("qemu-img")
|
||||
.args(&["resize", &image, "+5M"])
|
||||
.status()
|
||||
.unwrap()
|
||||
.exit_ok()
|
||||
.expect("FAILED: qemu-img resize");
|
||||
Qemu::img()
|
||||
.arg("resize")
|
||||
.args(&["-f", "raw"])
|
||||
.arg(image)
|
||||
.arg("+5M")
|
||||
.invoke();
|
||||
}
|
||||
|
||||
/// 获取 alpine 镜像。
|
||||
fn wget_alpine(&self) {
|
||||
let (local_path, web_url) = match self.command {
|
||||
ArchCommands::Riscv64 => {
|
||||
const ARCH: &str = "riscv64";
|
||||
const FILE_NAME: &str = "minirootfs.tar.xz";
|
||||
const WEB_URL: &str = "https://github.com/rcore-os/libc-test-prebuilt/releases/download/0.1/prebuild.tar.xz";
|
||||
fn rootfs(&self) -> PathBuf {
|
||||
let mut path = PathBuf::new();
|
||||
path.push("rootfs");
|
||||
path.push(self.arch.as_str());
|
||||
path
|
||||
}
|
||||
|
||||
let local_path = PathBuf::from(format!("prebuilt/linux/{ARCH}/{FILE_NAME}"));
|
||||
if local_path.exists() {
|
||||
return;
|
||||
}
|
||||
(local_path, WEB_URL.into())
|
||||
}
|
||||
ArchCommands::X86_64 => {
|
||||
const ARCH: &str = "x86_64";
|
||||
const FILE_NAME: &str = "minirootfs.tar.gz";
|
||||
fn libc_test(&self) -> PathBuf {
|
||||
let mut path = self.rootfs();
|
||||
path.push("libc-test");
|
||||
path
|
||||
}
|
||||
|
||||
let local_path = PathBuf::from(format!("prebuilt/linux/{ARCH}/{FILE_NAME}"));
|
||||
if local_path.exists() {
|
||||
return;
|
||||
}
|
||||
(
|
||||
local_path,
|
||||
format!(
|
||||
"{ALPINE_WEBSITE}/{ARCH}/alpine-minirootfs-{ALPINE_ROOTFS_VERSION}-{ARCH}.tar.gz"
|
||||
),
|
||||
)
|
||||
}
|
||||
fn origin(&self) -> PathBuf {
|
||||
let mut path = PathBuf::new();
|
||||
path.push("ignored");
|
||||
path.push("origin");
|
||||
path.push(self.arch.as_str());
|
||||
path
|
||||
}
|
||||
|
||||
fn target(&self) -> PathBuf {
|
||||
let mut path = PathBuf::new();
|
||||
path.push("ignored");
|
||||
path.push("target");
|
||||
path.push(self.arch.as_str());
|
||||
path
|
||||
}
|
||||
|
||||
/// 下载并解压 minirootfs。
|
||||
fn prebuild_rootfs(&self) -> PathBuf {
|
||||
// 构造压缩文件路径
|
||||
let file_name = match self.arch {
|
||||
Arch::Riscv64 => "minirootfs.tar.xz",
|
||||
Arch::X86_64 => "minirootfs.tar.gz",
|
||||
};
|
||||
|
||||
fs::create_dir_all(local_path.parent().unwrap()).unwrap();
|
||||
wget(&web_url, &local_path);
|
||||
}
|
||||
}
|
||||
|
||||
struct Make(Command);
|
||||
|
||||
impl AsRef<Command> for Make {
|
||||
fn as_ref(&self) -> &Command {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Command> for Make {
|
||||
fn as_mut(&mut self) -> &mut Command {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandExt for Make {}
|
||||
|
||||
impl Make {
|
||||
fn new(j: Option<usize>) -> Self {
|
||||
let mut make = Self(Command::new("make"));
|
||||
match j {
|
||||
Some(0) => {}
|
||||
Some(j) => {
|
||||
make.arg(format!("-j{j}"));
|
||||
}
|
||||
None => {
|
||||
make.arg("-j");
|
||||
}
|
||||
let tar = self.origin().join(file_name);
|
||||
// 若压缩文件不存在,需要下载
|
||||
if !tar.exists() {
|
||||
let url = match self.arch {
|
||||
Arch::Riscv64 => String::from("https://github.com/rcore-os/libc-test-prebuilt/releases/download/0.1/prebuild.tar.xz"),
|
||||
Arch::X86_64 => format!("{ALPINE_WEBSITE}/x86_64/alpine-minirootfs-{ALPINE_ROOTFS_VERSION}-x86_64.tar.gz"),
|
||||
};
|
||||
wget(url, &tar);
|
||||
}
|
||||
make
|
||||
}
|
||||
}
|
||||
|
||||
struct Tar(Command);
|
||||
|
||||
impl AsRef<Command> for Tar {
|
||||
fn as_ref(&self) -> &Command {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Command> for Tar {
|
||||
fn as_mut(&mut self) -> &mut Command {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandExt for Tar {}
|
||||
|
||||
impl Tar {
|
||||
fn xf(src: &impl AsRef<OsStr>, dst: Option<&str>) -> Self {
|
||||
let mut cmd = Command::new("tar");
|
||||
cmd.arg("xf").arg(src);
|
||||
if let Some(dst) = dst {
|
||||
cmd.arg("-C").arg(dst);
|
||||
// 解压到目标路径
|
||||
let dir = self.target().join("rootfs");
|
||||
dir::clear(&dir).unwrap();
|
||||
let mut tar = Tar::xf(&tar, Some(&dir));
|
||||
match self.arch {
|
||||
Arch::Riscv64 => tar.args(&["--strip-components", "1"]).invoke(),
|
||||
Arch::X86_64 => tar.invoke(),
|
||||
}
|
||||
Self(cmd)
|
||||
dir
|
||||
}
|
||||
}
|
||||
|
||||
/// 下载适用于 libos 的 musl libc so。
|
||||
fn libos_libc_so() -> PathBuf {
|
||||
const NAME: &str = "libc-libos.so";
|
||||
|
||||
let url =
|
||||
format!("https://github.com/rcore-os/libc-test-prebuilt/releases/download/master/{NAME}");
|
||||
let dst = ArchArg::X86_64.origin().join(NAME);
|
||||
wget(url, &dst);
|
||||
dst
|
||||
}
|
||||
|
||||
/// 下载 riscv64-musl 工具链。
|
||||
fn riscv64_linux_musl_cross() -> OsString {
|
||||
const DIR: &str = "ignored";
|
||||
const NAME: &str = "riscv64-linux-musl-cross";
|
||||
let dir = format!("{DIR}/{NAME}");
|
||||
let tgz = format!("{dir}.tgz");
|
||||
|
||||
wget(&format!("https://musl.cc/{NAME}.tgz"), &tgz);
|
||||
let origin = ArchArg::RISCV64.origin();
|
||||
let target = ArchArg::RISCV64.target();
|
||||
|
||||
let tgz = origin.join(format!("{NAME}.tgz"));
|
||||
let dir = target.join(NAME);
|
||||
|
||||
dir::rm(&dir).unwrap();
|
||||
Tar::xf(&tgz, Some(DIR)).join();
|
||||
wget(format!("https://musl.cc/{NAME}.tgz"), &tgz);
|
||||
Tar::xf(&tgz, Some(target)).invoke();
|
||||
|
||||
// 将交叉工具链加入 PATH 环境变量
|
||||
let mut path = OsString::new();
|
||||
|
@ -301,7 +250,9 @@ fn riscv64_linux_musl_cross() -> OsString {
|
|||
path.push(":");
|
||||
}
|
||||
path.push(std::env::current_dir().unwrap());
|
||||
path.push("/ignored/riscv64-linux-musl-cross/bin");
|
||||
path.push("/");
|
||||
path.push(dir);
|
||||
path.push("/bin");
|
||||
path
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
use crate::{
|
||||
arch::ArchArg,
|
||||
command::{Cargo, CommandExt, Ext, Qemu},
|
||||
Arch,
|
||||
};
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
#[derive(Args)]
|
||||
pub(crate) struct BuildArgs {
|
||||
#[clap(flatten)]
|
||||
arch: ArchArg,
|
||||
/// Build as debug mode.
|
||||
#[clap(long)]
|
||||
debug: bool,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub(crate) struct AsmArgs {
|
||||
#[clap(flatten)]
|
||||
build: BuildArgs,
|
||||
/// The file to save asm.
|
||||
#[clap(short, long)]
|
||||
output: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub(crate) struct QemuArgs {
|
||||
#[clap(flatten)]
|
||||
build: BuildArgs,
|
||||
/// Number of hart (SMP for Symmetrical Multiple Processor).
|
||||
#[clap(long)]
|
||||
smp: Option<u8>,
|
||||
/// Port for gdb to connect. If set, qemu will block and wait gdb to connect.
|
||||
#[clap(long)]
|
||||
gdb: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub(crate) struct GdbArgs {
|
||||
#[clap(flatten)]
|
||||
arch: ArchArg,
|
||||
#[clap(long)]
|
||||
port: u16,
|
||||
}
|
||||
|
||||
impl BuildArgs {
|
||||
fn arch(&self) -> Arch {
|
||||
self.arch.arch
|
||||
}
|
||||
|
||||
fn dir(&self) -> String {
|
||||
format!(
|
||||
"target/{arch}/{mode}",
|
||||
arch = self.arch().as_str(),
|
||||
mode = if self.debug { "debug" } else { "release" }
|
||||
)
|
||||
}
|
||||
|
||||
fn build(&self) {
|
||||
let mut cargo = Cargo::build();
|
||||
cargo
|
||||
.package("zcore")
|
||||
.features(false, &["linux", "board-qemu"])
|
||||
.target(format!("zCore/{arch}.json", arch = self.arch().as_str()))
|
||||
.args(&["-Z", "build-std=core,alloc"])
|
||||
.args(&["-Z", "build-std-features=compiler-builtins-mem"]);
|
||||
if !self.debug {
|
||||
cargo.release();
|
||||
}
|
||||
cargo.invoke();
|
||||
}
|
||||
}
|
||||
|
||||
impl AsmArgs {
|
||||
/// 打印 asm。
|
||||
pub fn asm(&self) {
|
||||
// 递归 build
|
||||
self.build.build();
|
||||
let out = Ext::new("rust-objdump")
|
||||
.arg(format!("{dir}/zcore", dir = self.build.dir()))
|
||||
.arg("-d")
|
||||
.output()
|
||||
.stdout;
|
||||
fs::write(&self.output, out).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl QemuArgs {
|
||||
/// 在 qemu 中启动。
|
||||
pub fn qemu(&self) {
|
||||
// 递归 image
|
||||
self.build.arch.image();
|
||||
// 递归 build
|
||||
self.build.build();
|
||||
// 构造各种字符串
|
||||
let arch = self.build.arch();
|
||||
let arch_str = arch.as_str();
|
||||
let dir = self.build.dir();
|
||||
let obj = format!("{dir}/zcore");
|
||||
let bin = format!("{dir}/zcore.bin");
|
||||
// 裁剪内核二进制文件
|
||||
Ext::new("rust-objcopy")
|
||||
.arg(format!("--binary-architecture={arch_str}"))
|
||||
.arg(obj)
|
||||
.arg("--strip-all")
|
||||
.args(&["-O", "binary", &bin])
|
||||
.invoke();
|
||||
// 设置 Qemu 参数
|
||||
let mut qemu = Qemu::system(arch);
|
||||
qemu.args(&["-m", "512M"])
|
||||
.args(&["-kernel", &bin])
|
||||
.args(&["-initrd", &format!("zCore/{arch_str}.img")])
|
||||
.args(&["-append", "\"LOG=warn\""])
|
||||
.args(&["-display", "none"])
|
||||
.arg("-no-reboot")
|
||||
.arg("-nographic");
|
||||
if let Some(smp) = self.smp {
|
||||
qemu.args(&["-smp", &smp.to_string()]);
|
||||
}
|
||||
match arch {
|
||||
Arch::Riscv64 => {
|
||||
qemu.args(&["-machine", "virt"])
|
||||
.arg("-bios")
|
||||
.arg(rustsbi_qemu())
|
||||
.args(&["-serial", "mon:stdio"]);
|
||||
}
|
||||
Arch::X86_64 => todo!(),
|
||||
}
|
||||
if let Some(port) = self.gdb {
|
||||
qemu.args(&["-S", "-gdb", &format!("tcp::{port}")]);
|
||||
}
|
||||
qemu.invoke();
|
||||
}
|
||||
}
|
||||
|
||||
impl GdbArgs {
|
||||
pub fn gdb(&self) {
|
||||
match self.arch.arch {
|
||||
Arch::Riscv64 => {
|
||||
Ext::new("riscv64-unknown-elf-gdb")
|
||||
.args(&["-ex", &format!("target remote localhost:{}", self.port)])
|
||||
.invoke();
|
||||
}
|
||||
Arch::X86_64 => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 下载 rustsbi。
|
||||
fn rustsbi_qemu() -> PathBuf {
|
||||
// const NAME: &str = "rustsbi-qemu-release";
|
||||
|
||||
// let origin = Arch::Riscv64.origin();
|
||||
// let target = Arch::Riscv64.target();
|
||||
|
||||
// let zip = origin.join(format!("{NAME}.zip"));
|
||||
// let dir = target.join(NAME);
|
||||
// let url =
|
||||
// format!("https://github.com/rustsbi/rustsbi-qemu/releases/download/v0.1.1/{NAME}.zip");
|
||||
|
||||
// dir::rm(&dir).unwrap();
|
||||
// wget(url, &zip);
|
||||
// Ext::new("unzip").arg("-d").arg(&dir).arg(zip).invoke();
|
||||
|
||||
// dir.join("rustsbi-qemu.bin")
|
||||
PathBuf::from("default")
|
||||
// PathBuf::from("../rustsbi-qemu/target/riscv64imac-unknown-none-elf/release/rustsbi-qemu.bin")
|
||||
}
|
|
@ -1,29 +1,13 @@
|
|||
use crate::CommandExt;
|
||||
use super::{ext, CommandExt};
|
||||
use std::{ffi::OsStr, process::Command};
|
||||
|
||||
pub(crate) struct Cargo {
|
||||
cmd: Command,
|
||||
}
|
||||
pub(crate) struct Cargo(Command);
|
||||
|
||||
impl AsRef<Command> for Cargo {
|
||||
fn as_ref(&self) -> &Command {
|
||||
&self.cmd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Command> for Cargo {
|
||||
fn as_mut(&mut self) -> &mut Command {
|
||||
&mut self.cmd
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandExt for Cargo {}
|
||||
ext!(Cargo);
|
||||
|
||||
impl Cargo {
|
||||
fn new(sub: &(impl AsRef<OsStr> + ?Sized)) -> Self {
|
||||
let mut git = Self {
|
||||
cmd: Command::new("cargo"),
|
||||
};
|
||||
let mut git = Self(Command::new("cargo"));
|
||||
git.arg(sub);
|
||||
git
|
||||
}
|
||||
|
@ -40,6 +24,14 @@ impl Cargo {
|
|||
Self::new("clippy")
|
||||
}
|
||||
|
||||
pub fn doc() -> Self {
|
||||
Self::new("doc")
|
||||
}
|
||||
|
||||
pub fn build() -> Self {
|
||||
Self::new("build")
|
||||
}
|
||||
|
||||
pub fn all_features(&mut self) -> &mut Self {
|
||||
self.arg("--all-features");
|
||||
self
|
||||
|
@ -72,4 +64,14 @@ impl Cargo {
|
|||
self.arg("--target").arg(target);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn package(&mut self, package: impl AsRef<OsStr>) -> &mut Self {
|
||||
self.arg("--package").arg(package);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn release(&mut self) -> &mut Self {
|
||||
self.arg("--release");
|
||||
self
|
||||
}
|
||||
}
|
|
@ -1,33 +1,45 @@
|
|||
//! 操作目录。
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
/// 删除指定路径。
|
||||
///
|
||||
/// 如果返回 `Ok(())`,`path` 将不存在。
|
||||
pub fn rm(path: &(impl AsRef<Path> + ?Sized)) -> std::io::Result<()> {
|
||||
pub fn rm(path: impl AsRef<Path>) -> std::io::Result<()> {
|
||||
let path = path.as_ref();
|
||||
if !path.exists() {
|
||||
Ok(())
|
||||
} else if path.is_dir() {
|
||||
std::fs::remove_dir_all(path)
|
||||
fs::remove_dir_all(path)
|
||||
} else {
|
||||
std::fs::remove_file(path)
|
||||
fs::remove_file(path)
|
||||
}
|
||||
}
|
||||
|
||||
/// 创建 `path` 的父目录。
|
||||
pub fn create_parent(path: impl AsRef<Path>) -> std::io::Result<()> {
|
||||
match path.as_ref().parent() {
|
||||
Some(parent) => fs::create_dir_all(parent),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// 清理 `path` 目录。
|
||||
///
|
||||
/// 如果返回 `Ok(())`,`path` 将是一个存在的空目录。
|
||||
pub fn clear(path: &(impl AsRef<Path> + ?Sized)) -> std::io::Result<()> {
|
||||
rm(path)?;
|
||||
std::fs::create_dir_all(path)
|
||||
pub fn clear(path: impl AsRef<Path>) -> std::io::Result<()> {
|
||||
rm(&path)?;
|
||||
std::fs::create_dir_all(&path)
|
||||
}
|
||||
|
||||
/// 在 `dir` 目录中根据文件名前半部分 `prefix` 找到对应文件。
|
||||
///
|
||||
/// 不会递归查找。
|
||||
pub fn detect(path: &(impl AsRef<Path> + ?Sized), prefix: &str) -> Option<PathBuf> {
|
||||
#[allow(unused)]
|
||||
pub fn detect(path: impl AsRef<Path>, prefix: impl AsRef<str>) -> Option<PathBuf> {
|
||||
path.as_ref()
|
||||
.read_dir()
|
||||
.ok()?
|
||||
|
@ -37,6 +49,6 @@ pub fn detect(path: &(impl AsRef<Path> + ?Sized), prefix: &str) -> Option<PathBu
|
|||
.find(|path| {
|
||||
path.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.map_or(false, |s| s.starts_with(prefix))
|
||||
.map_or(false, |s| s.starts_with(prefix.as_ref()))
|
||||
})
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{dir, git::Git, CommandExt};
|
||||
use super::{dir, git::Git, CommandExt};
|
||||
use std::{ffi::OsStr, fs, path::Path, process::Command};
|
||||
|
||||
pub(crate) fn wget(url: impl AsRef<OsStr>, dst: impl AsRef<Path>) {
|
||||
|
@ -15,9 +15,11 @@ pub(crate) fn wget(url: impl AsRef<OsStr>, dst: impl AsRef<Path>) {
|
|||
.status()
|
||||
.unwrap();
|
||||
if status.success() {
|
||||
fs::rename(&tmp, dst).unwrap();
|
||||
dir::create_parent(&dst).unwrap();
|
||||
fs::copy(&tmp, dst).unwrap();
|
||||
dir::rm(tmp).unwrap();
|
||||
} else {
|
||||
dir::rm(&tmp).unwrap();
|
||||
dir::rm(tmp).unwrap();
|
||||
panic!(
|
||||
"Failed with code {}: wget {:?}",
|
||||
status.code().unwrap(),
|
||||
|
@ -26,10 +28,11 @@ pub(crate) fn wget(url: impl AsRef<OsStr>, dst: impl AsRef<Path>) {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn git_clone(repo: impl AsRef<OsStr>, dst: impl AsRef<Path>) {
|
||||
let dst = dst.as_ref();
|
||||
if dst.is_dir() {
|
||||
Git::pull().current_dir(dst).join();
|
||||
Git::pull().current_dir(dst).invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -38,10 +41,11 @@ pub(crate) fn git_clone(repo: impl AsRef<OsStr>, dst: impl AsRef<Path>) {
|
|||
let mut git = Git::clone(repo, Some(&tmp));
|
||||
let status = git.status();
|
||||
if status.success() {
|
||||
dir::clear(dst).unwrap();
|
||||
fs::rename(&tmp, dst).unwrap();
|
||||
dir::create_parent(&dst).unwrap();
|
||||
dircpy::copy_dir(&tmp, dst).unwrap();
|
||||
dir::rm(tmp).unwrap();
|
||||
} else {
|
||||
dir::rm(&tmp).unwrap();
|
||||
dir::rm(tmp).unwrap();
|
||||
panic!(
|
||||
"Failed with code {}: {:?}",
|
||||
status.code().unwrap(),
|
|
@ -1,31 +1,15 @@
|
|||
//! 操作 git。
|
||||
|
||||
use crate::CommandExt;
|
||||
use super::{ext, CommandExt};
|
||||
use std::{ffi::OsStr, process::Command};
|
||||
|
||||
pub(super) struct Git {
|
||||
cmd: Command,
|
||||
}
|
||||
pub(crate) struct Git(Command);
|
||||
|
||||
impl AsRef<Command> for Git {
|
||||
fn as_ref(&self) -> &Command {
|
||||
&self.cmd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Command> for Git {
|
||||
fn as_mut(&mut self) -> &mut Command {
|
||||
&mut self.cmd
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandExt for Git {}
|
||||
ext!(Git);
|
||||
|
||||
impl Git {
|
||||
fn new(sub: impl AsRef<OsStr>) -> Self {
|
||||
let mut git = Self {
|
||||
cmd: Command::new("git"),
|
||||
};
|
||||
let mut git = Self(Command::new("git"));
|
||||
git.arg(sub);
|
||||
git
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
use super::{ext, CommandExt};
|
||||
use std::process::Command;
|
||||
|
||||
pub(crate) struct Make(Command);
|
||||
|
||||
ext!(Make);
|
||||
|
||||
impl Make {
|
||||
pub fn new(j: Option<usize>) -> Self {
|
||||
let mut make = Self(Command::new("make"));
|
||||
match j {
|
||||
Some(0) => {}
|
||||
Some(j) => {
|
||||
make.arg(format!("-j{j}"));
|
||||
}
|
||||
None => {
|
||||
make.arg("-j");
|
||||
}
|
||||
}
|
||||
make
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
use m::ext;
|
||||
use std::{
|
||||
ffi::{OsStr, OsString},
|
||||
path::Path,
|
||||
process::{Command, ExitStatus, Output},
|
||||
};
|
||||
|
||||
mod cargo;
|
||||
pub mod dir;
|
||||
pub mod download;
|
||||
mod git;
|
||||
mod make;
|
||||
mod qemu;
|
||||
mod tar;
|
||||
|
||||
pub(crate) use cargo::Cargo;
|
||||
pub(crate) use git::Git;
|
||||
pub(crate) use make::Make;
|
||||
pub(crate) use qemu::Qemu;
|
||||
pub(crate) use tar::Tar;
|
||||
|
||||
pub(crate) trait CommandExt: AsRef<Command> + AsMut<Command> {
|
||||
fn arg(&mut self, s: impl AsRef<OsStr>) -> &mut Self {
|
||||
self.as_mut().arg(s);
|
||||
self
|
||||
}
|
||||
|
||||
fn args<I, S>(&mut self, args: I) -> &mut Self
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: AsRef<OsStr>,
|
||||
{
|
||||
for arg in args {
|
||||
self.arg(arg);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
fn current_dir(&mut self, dir: impl AsRef<Path>) -> &mut Self {
|
||||
self.as_mut().current_dir(dir);
|
||||
self
|
||||
}
|
||||
|
||||
fn env(&mut self, key: impl AsRef<OsStr>, val: impl AsRef<OsStr>) -> &mut Self {
|
||||
self.as_mut().env(key, val);
|
||||
self
|
||||
}
|
||||
|
||||
fn status(&mut self) -> ExitStatus {
|
||||
self.as_mut().status().unwrap()
|
||||
}
|
||||
|
||||
fn info(&self) -> OsString {
|
||||
let cmd = self.as_ref();
|
||||
let mut msg = OsString::new();
|
||||
if let Some(dir) = cmd.get_current_dir() {
|
||||
msg.push("cd ");
|
||||
msg.push(dir);
|
||||
msg.push(" && ");
|
||||
}
|
||||
msg.push(cmd.get_program());
|
||||
for a in cmd.get_args() {
|
||||
msg.push(" ");
|
||||
msg.push(a);
|
||||
}
|
||||
for (k, v) in cmd.get_envs() {
|
||||
msg.push(" ");
|
||||
msg.push(k);
|
||||
if let Some(v) = v {
|
||||
msg.push("=");
|
||||
msg.push(v);
|
||||
}
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
fn invoke(&mut self) {
|
||||
let status = self.status();
|
||||
if !status.success() {
|
||||
panic!(
|
||||
"Failed with code {}: {:?}",
|
||||
status.code().unwrap(),
|
||||
self.info()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn output(&mut self) -> Output {
|
||||
let output = self.as_mut().output().unwrap();
|
||||
if !output.status.success() {
|
||||
panic!(
|
||||
"Failed with code {}: {:?}",
|
||||
output.status.code().unwrap(),
|
||||
self.info()
|
||||
);
|
||||
}
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Ext(Command);
|
||||
|
||||
ext!(Ext);
|
||||
|
||||
impl Ext {
|
||||
pub fn new(program: impl AsRef<OsStr>) -> Self {
|
||||
Self(Command::new(program))
|
||||
}
|
||||
}
|
||||
|
||||
mod m {
|
||||
macro_rules! ext {
|
||||
($ty:ty) => {
|
||||
impl AsRef<Command> for $ty {
|
||||
fn as_ref(&self) -> &Command {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Command> for $ty {
|
||||
fn as_mut(&mut self) -> &mut Command {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl super::CommandExt for $ty {}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use ext;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
use super::ext;
|
||||
use crate::Arch;
|
||||
use std::process::Command;
|
||||
|
||||
pub(crate) struct Qemu(Command);
|
||||
|
||||
ext!(Qemu);
|
||||
|
||||
impl Qemu {
|
||||
pub fn img() -> Self {
|
||||
Self(Command::new("qemu-img"))
|
||||
}
|
||||
|
||||
pub fn system(arch: Arch) -> Self {
|
||||
Self(Command::new(format!("qemu-system-{}", arch.as_str())))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
use super::ext;
|
||||
use std::{ffi::OsStr, process::Command};
|
||||
|
||||
pub(crate) struct Tar(Command);
|
||||
|
||||
ext!(Tar);
|
||||
|
||||
impl Tar {
|
||||
pub fn xf(src: &impl AsRef<OsStr>, dst: Option<impl AsRef<OsStr>>) -> Self {
|
||||
let mut cmd = Command::new("tar");
|
||||
cmd.arg("xf").arg(src);
|
||||
if let Some(dst) = dst {
|
||||
cmd.arg("-C").arg(dst);
|
||||
}
|
||||
Self(cmd)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
use crate::XError;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum Arch {
|
||||
Riscv64,
|
||||
X86_64,
|
||||
}
|
||||
|
||||
impl Arch {
|
||||
pub const fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Riscv64 => "riscv64",
|
||||
Self::X86_64 => "x86_64",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Arch {
|
||||
type Err = XError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"riscv64" => Ok(Self::Riscv64),
|
||||
"x86_64" => Ok(Self::X86_64),
|
||||
_ => Err(XError::EnumParse {
|
||||
type_name: "Arch",
|
||||
value: s.into(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum XError {
|
||||
EnumParse {
|
||||
type_name: &'static str,
|
||||
value: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl Display for XError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
XError::EnumParse { type_name, value } => {
|
||||
write!(f, "Parse {type_name} from {value} failed.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for XError {}
|
|
@ -5,25 +5,22 @@
|
|||
extern crate clap;
|
||||
|
||||
use clap::Parser;
|
||||
use clap_verbosity_flag::Verbosity;
|
||||
use std::{
|
||||
ffi::{OsStr, OsString},
|
||||
fs::read_to_string,
|
||||
net::Ipv4Addr,
|
||||
path::Path,
|
||||
process::{Command, ExitStatus},
|
||||
};
|
||||
use std::{fs::read_to_string, net::Ipv4Addr};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod dump;
|
||||
|
||||
mod arch;
|
||||
mod cargo;
|
||||
mod dir;
|
||||
mod download;
|
||||
mod dump;
|
||||
mod git;
|
||||
mod build;
|
||||
mod command;
|
||||
mod enums;
|
||||
mod errors;
|
||||
|
||||
use arch::Arch;
|
||||
use cargo::Cargo;
|
||||
use git::Git;
|
||||
use arch::ArchArg;
|
||||
use build::{AsmArgs, GdbArgs, QemuArgs};
|
||||
use command::{Cargo, CommandExt, Ext, Git, Make};
|
||||
use enums::*;
|
||||
use errors::XError;
|
||||
|
||||
const ALPINE_WEBSITE: &str = "https://dl-cdn.alpinelinux.org/alpine/v3.12/releases";
|
||||
const ALPINE_ROOTFS_VERSION: &str = "3.12.0";
|
||||
|
@ -35,10 +32,6 @@ const ALPINE_ROOTFS_VERSION: &str = "3.12.0";
|
|||
struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
#[clap(flatten)]
|
||||
env: Env,
|
||||
#[clap(flatten)]
|
||||
verbose: Verbosity,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
|
@ -48,6 +41,9 @@ enum Commands {
|
|||
/// Input your proxy port to set the proxy,
|
||||
/// or leave blank to unset it.
|
||||
GitProxy(ProxyPort),
|
||||
/// Dump build config.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
Dump,
|
||||
|
||||
/// First time running.
|
||||
Setup,
|
||||
|
@ -57,25 +53,20 @@ enum Commands {
|
|||
CheckStyle,
|
||||
|
||||
/// Build rootfs
|
||||
Rootfs(Arch),
|
||||
/// Put libc-test.
|
||||
LibcTest(Arch),
|
||||
Rootfs(ArchArg),
|
||||
/// Put libc test into rootfs.
|
||||
LibcTest(ArchArg),
|
||||
/// Put other test into rootfs.
|
||||
OtherTest(ArchArg),
|
||||
/// Build image
|
||||
Image(Arch),
|
||||
Image(ArchArg),
|
||||
|
||||
/// Unit test
|
||||
Test,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct Env {
|
||||
/// Build in release mode.
|
||||
#[clap(short, long, global = true)]
|
||||
release: bool,
|
||||
|
||||
/// Dump build config.
|
||||
#[clap(short, long, global = true)]
|
||||
dump: bool,
|
||||
/// Dump asm of kernel
|
||||
Asm(AsmArgs),
|
||||
/// Run zCore in qemu
|
||||
Qemu(QemuArgs),
|
||||
/// Launch GDB
|
||||
Gdb(GdbArgs),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
|
@ -89,13 +80,7 @@ struct ProxyPort {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
|
||||
if cli.env.dump {
|
||||
dump::dump_config();
|
||||
}
|
||||
|
||||
match cli.command {
|
||||
match Cli::parse().command {
|
||||
Commands::GitProxy(ProxyPort { port, global }) => {
|
||||
if let Some(port) = port {
|
||||
set_git_proxy(global, port);
|
||||
|
@ -103,16 +88,21 @@ fn main() {
|
|||
unset_git_proxy(global);
|
||||
}
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
Commands::Dump => dump::dump_config(),
|
||||
Commands::Setup => {
|
||||
make_git_lfs();
|
||||
git_submodule_update(true);
|
||||
}
|
||||
Commands::UpdateAll => update_all(),
|
||||
Commands::CheckStyle => check_style(),
|
||||
Commands::Rootfs(arch) => arch.rootfs(true),
|
||||
Commands::LibcTest(arch) => arch.libc_test(),
|
||||
Commands::Image(arch) => arch.image(),
|
||||
Commands::Test => todo!(),
|
||||
Commands::Rootfs(arg) => arg.make_rootfs(true),
|
||||
Commands::LibcTest(arg) => arg.put_libc_test(),
|
||||
Commands::OtherTest(arg) => arg.put_other_test(),
|
||||
Commands::Image(arg) => arg.image(),
|
||||
Commands::Asm(args) => args.asm(),
|
||||
Commands::Qemu(args) => args.qemu(),
|
||||
Commands::Gdb(args) => args.gdb(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,25 +116,20 @@ fn make_git_lfs() {
|
|||
{
|
||||
panic!("Cannot find git lfs, see https://git-lfs.github.com/ for help.");
|
||||
}
|
||||
Git::lfs().arg("install").join();
|
||||
Git::lfs().arg("pull").join();
|
||||
Git::lfs().arg("install").invoke();
|
||||
Git::lfs().arg("pull").invoke();
|
||||
}
|
||||
|
||||
/// 更新子项目。
|
||||
fn git_submodule_update(init: bool) {
|
||||
Git::submodule_update(init).join();
|
||||
Git::submodule_update(init).invoke();
|
||||
}
|
||||
|
||||
/// 更新工具链和依赖。
|
||||
fn update_all() {
|
||||
git_submodule_update(false);
|
||||
Command::new("rustup")
|
||||
.arg("update")
|
||||
.status()
|
||||
.unwrap()
|
||||
.exit_ok()
|
||||
.expect("FAILED: rustup update");
|
||||
Cargo::update().join();
|
||||
Ext::new("rustup").arg("update").invoke();
|
||||
Cargo::update().invoke();
|
||||
}
|
||||
|
||||
/// 设置 git 代理。
|
||||
|
@ -158,108 +143,49 @@ fn set_git_proxy(global: bool, port: u16) {
|
|||
})
|
||||
.expect("FAILED: detect DNS");
|
||||
let proxy = format!("socks5://{dns}:{port}");
|
||||
Git::config(global).args(&["http.proxy", &proxy]).join();
|
||||
Git::config(global).args(&["http.proxy", &proxy]).join();
|
||||
Git::config(global).args(&["http.proxy", &proxy]).invoke();
|
||||
Git::config(global).args(&["https.proxy", &proxy]).invoke();
|
||||
println!("git proxy = {proxy}");
|
||||
}
|
||||
|
||||
/// 移除 git 代理。
|
||||
fn unset_git_proxy(global: bool) {
|
||||
Git::config(global).args(&["--unset", "http.proxy"]).join();
|
||||
Git::config(global).args(&["--unset", "https.proxy"]).join();
|
||||
Git::config(global)
|
||||
.args(&["--unset", "http.proxy"])
|
||||
.invoke();
|
||||
Git::config(global)
|
||||
.args(&["--unset", "https.proxy"])
|
||||
.invoke();
|
||||
println!("git proxy =");
|
||||
}
|
||||
|
||||
/// 风格检查。
|
||||
fn check_style() {
|
||||
println!("fmt -----------------------------------------");
|
||||
Cargo::fmt().arg("--all").arg("--").arg("--check").join();
|
||||
println!("clippy --------------------------------------");
|
||||
Cargo::clippy().all_features().join();
|
||||
println!("clippy x86_64 zircon smp=1 ------------------");
|
||||
println!("Check workspace");
|
||||
Cargo::fmt().arg("--all").arg("--").arg("--check").invoke();
|
||||
Cargo::clippy().all_features().invoke();
|
||||
Cargo::doc().all_features().arg("--no-deps").invoke();
|
||||
|
||||
println!("Check libos");
|
||||
Cargo::clippy()
|
||||
.features(false, &["zircon"])
|
||||
.target("x86_64.json")
|
||||
.args(&["-Z", "build-std=core,alloc"])
|
||||
.args(&["-Z", "build-std-features=compiler-builtins-mem"])
|
||||
.current_dir("zCore")
|
||||
.env("SMP", "1")
|
||||
.join();
|
||||
println!("clippy riscv64 linux smp=4 ------------------");
|
||||
.package("zcore")
|
||||
.features(false, &["zircon", "libos"])
|
||||
.invoke();
|
||||
Cargo::clippy()
|
||||
.features(false, &["linux", "board-qemu"])
|
||||
.target("riscv64.json")
|
||||
.args(&["-Z", "build-std=core,alloc"])
|
||||
.args(&["-Z", "build-std-features=compiler-builtins-mem"])
|
||||
.package("zcore")
|
||||
.features(false, &["linux", "libos"])
|
||||
.invoke();
|
||||
|
||||
println!("Check bare-metal");
|
||||
Make::new(None)
|
||||
.arg("clippy")
|
||||
.env("ARCH", "x86_64")
|
||||
.current_dir("zCore")
|
||||
.env("SMP", "4")
|
||||
.env("PLATFORM", "board-qemu")
|
||||
.join();
|
||||
}
|
||||
|
||||
trait CommandExt: AsRef<Command> + AsMut<Command> {
|
||||
fn arg(&mut self, s: impl AsRef<OsStr>) -> &mut Self {
|
||||
self.as_mut().arg(s);
|
||||
self
|
||||
}
|
||||
|
||||
fn args<I, S>(&mut self, args: I) -> &mut Self
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: AsRef<OsStr>,
|
||||
{
|
||||
for arg in args {
|
||||
self.arg(arg);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
fn current_dir(&mut self, dir: impl AsRef<Path>) -> &mut Self {
|
||||
self.as_mut().current_dir(dir);
|
||||
self
|
||||
}
|
||||
|
||||
fn env(&mut self, key: impl AsRef<OsStr>, val: impl AsRef<OsStr>) -> &mut Self {
|
||||
self.as_mut().env(key, val);
|
||||
self
|
||||
}
|
||||
|
||||
fn status(&mut self) -> ExitStatus {
|
||||
self.as_mut().status().unwrap()
|
||||
}
|
||||
|
||||
fn info(&self) -> OsString {
|
||||
let cmd = self.as_ref();
|
||||
let mut msg = OsString::new();
|
||||
if let Some(dir) = cmd.get_current_dir() {
|
||||
msg.push("cd ");
|
||||
msg.push(dir);
|
||||
msg.push(" && ");
|
||||
}
|
||||
msg.push(cmd.get_program());
|
||||
for a in cmd.get_args() {
|
||||
msg.push(" ");
|
||||
msg.push(a);
|
||||
}
|
||||
for (k, v) in cmd.get_envs() {
|
||||
msg.push(" ");
|
||||
msg.push(k);
|
||||
if let Some(v) = v {
|
||||
msg.push("=");
|
||||
msg.push(v);
|
||||
}
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
fn join(&mut self) {
|
||||
let status = self.status();
|
||||
if !status.success() {
|
||||
panic!(
|
||||
"Failed with code {}: {:?}",
|
||||
status.code().unwrap(),
|
||||
self.info()
|
||||
);
|
||||
}
|
||||
}
|
||||
.invoke();
|
||||
Make::new(None)
|
||||
.arg("clippy")
|
||||
.env("ARCH", "riscv64")
|
||||
.env("LINUX", "1")
|
||||
.current_dir("zCore")
|
||||
.invoke();
|
||||
}
|
||||
|
|
|
@ -3,4 +3,9 @@ set architecture riscv:rv64
|
|||
target remote 127.0.0.1:15234
|
||||
symbol-file ../target/riscv64/release/zcore
|
||||
display/10i $pc
|
||||
break *0x8020004a
|
||||
# tbreak *(&jump_higher - 0xffffffff00000000)
|
||||
tbreak *0x802623b4
|
||||
c
|
||||
si
|
||||
si
|
||||
si
|
||||
|
|
|
@ -201,11 +201,15 @@ else
|
|||
qemu_opts += -display none -nographic
|
||||
endif
|
||||
|
||||
ifeq ($(ACCEL), 1)
|
||||
ifeq ($(shell uname), Darwin)
|
||||
qemu_opts += -accel hvf
|
||||
else
|
||||
qemu_opts += -accel kvm -cpu host,migratable=no,+invtsc
|
||||
ifeq ($(ARCH), x86_64)
|
||||
ifeq ($(PLATFORM), qemu)
|
||||
ifeq ($(ACCEL), 1)
|
||||
ifeq ($(shell uname), Darwin)
|
||||
qemu_opts += -accel hvf
|
||||
else
|
||||
qemu_opts += -accel kvm -cpu host,migratable=no,+invtsc
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -240,13 +244,13 @@ endif
|
|||
|
||||
ifeq ($(ARCH), x86_64)
|
||||
gdb := gdb
|
||||
else
|
||||
else
|
||||
gdb := riscv64-unknown-elf-gdb
|
||||
endif
|
||||
|
||||
.PHONY: debugrun
|
||||
debugrun: $(qemu_disk)
|
||||
cp .gdbinit_$(MODE) .gdbinit
|
||||
cp .gdbinit_$(ARCH) .gdbinit
|
||||
ifeq ($(ARCH), x86_64)
|
||||
$(sed) 's#initramfs=.*#initramfs=\\EFI\\zCore\\$(notdir $(user_img))#' $(esp)/EFI/Boot/rboot.conf
|
||||
$(sed) 's#cmdline=.*#cmdline=$(CMDLINE)#' $(esp)/EFI/Boot/rboot.conf
|
||||
|
@ -308,7 +312,7 @@ ifeq ($(PLATFORM), d1)
|
|||
run_d1: build
|
||||
$(OBJCOPY) ../prebuilt/firmware/d1/fw_payload.elf --strip-all -O binary ./zcore_d1.bin
|
||||
dd if=$(kernel_img) of=zcore_d1.bin bs=512 seek=2048
|
||||
xfel ddr ddr3
|
||||
xfel ddr d1
|
||||
xfel write 0x40000000 zcore_d1.bin
|
||||
xfel exec 0x40000000
|
||||
endif
|
||||
|
|
|
@ -4,11 +4,10 @@ fn main() {
|
|||
//println!("cargo:rerun-if-env-changed=PLATFORM");
|
||||
|
||||
if std::env::var("TARGET").unwrap().contains("riscv64") {
|
||||
let board = std::env::var("PLATFORM").unwrap();
|
||||
let kernel_base_addr: u64 = if board.contains("d1") {
|
||||
let kernel_base_addr: u64 = if std::env::var("PLATFORM").map_or(false, |p| p.contains("d1"))
|
||||
{
|
||||
0xffffffffc0100000
|
||||
} else {
|
||||
// opensbi仍旧把kernel放在0x80200000物理内存中
|
||||
0xffffffff80200000
|
||||
};
|
||||
|
||||
|
|
|
@ -1,22 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
fn init_ram_disk() -> Option<&'static mut [u8]> {
|
||||
if cfg!(feature = "link-user-img") {
|
||||
extern "C" {
|
||||
fn _user_img_start();
|
||||
fn _user_img_end();
|
||||
}
|
||||
Some(unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
_user_img_start as *mut u8,
|
||||
_user_img_end as usize - _user_img_start as usize,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
kernel_hal::boot::init_ram_disk()
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "linux")] {
|
||||
use alloc::sync::Arc;
|
||||
|
@ -24,12 +5,14 @@ cfg_if! {
|
|||
|
||||
#[cfg(feature = "libos")]
|
||||
pub fn rootfs() -> Arc<dyn FileSystem> {
|
||||
let base = if let Ok(dir) = std::env::var("CARGO_MANIFEST_DIR") {
|
||||
let mut rootfs = if let Ok(dir) = std::env::var("CARGO_MANIFEST_DIR") {
|
||||
std::path::Path::new(&dir).join("..")
|
||||
} else {
|
||||
std::env::current_dir().unwrap()
|
||||
};
|
||||
rcore_fs_hostfs::HostFS::new(base.join("rootfs"))
|
||||
rootfs.push("rootfs");
|
||||
rootfs.push(std::env::consts::ARCH);
|
||||
rcore_fs_hostfs::HostFS::new(rootfs)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "libos"))]
|
||||
|
@ -61,6 +44,24 @@ cfg_if! {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "libos"))]
|
||||
fn init_ram_disk() -> Option<&'static mut [u8]> {
|
||||
if cfg!(feature = "link-user-img") {
|
||||
extern "C" {
|
||||
fn _user_img_start();
|
||||
fn _user_img_end();
|
||||
}
|
||||
Some(unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
_user_img_start as *mut u8,
|
||||
_user_img_end as usize - _user_img_start as usize,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
kernel_hal::boot::init_ram_disk()
|
||||
}
|
||||
}
|
||||
|
||||
// Hard link rootfs img
|
||||
#[cfg(not(feature = "libos"))]
|
||||
#[cfg(feature = "link-user-img")]
|
||||
|
|
|
@ -10,7 +10,7 @@ fn panic(info: &PanicInfo) -> ! {
|
|||
println!("\n\n{info}");
|
||||
error!("\n\n{info}");
|
||||
|
||||
if cfg!(feature = "baremetal-test") {
|
||||
if cfg!(any(feature = "baremetal-test", feature = "board-qemu")) {
|
||||
kernel_hal::cpu::reset();
|
||||
} else {
|
||||
loop {
|
||||
|
|
|
@ -59,7 +59,9 @@ fn primary_main(config: kernel_hal::KernelConfig) {
|
|||
|
||||
#[cfg(not(any(feature = "libos", target_arch = "aarch64")))]
|
||||
fn secondary_main() -> ! {
|
||||
while !STARTED.load(Ordering::SeqCst) {}
|
||||
while !STARTED.load(Ordering::SeqCst) {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
// Don't print anything between previous line and next line.
|
||||
// Boot hart has initialized the UART chip, so we will use
|
||||
// UART for output instead of SBI, but the current HART is
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
pub mod consts;
|
||||
pub mod entry;
|
||||
pub mod consts;
|
|
@ -50,8 +50,8 @@ impl BootPageTable {
|
|||
// 设置线程指针
|
||||
asm!("mv tp, {}", in(reg) hartid);
|
||||
// 设置内核可访问用户页
|
||||
let sstatus: usize;
|
||||
asm!("csrrsi {}, sstatus, 18", out(reg) sstatus);
|
||||
let mut sstatus = 1usize << 18;
|
||||
asm!("csrrs {0}, sstatus, {0}", inlateout(reg) sstatus);
|
||||
sstatus
|
||||
}
|
||||
|
||||
|
|
|
@ -11,5 +11,6 @@ cfg_if! {
|
|||
}
|
||||
|
||||
pub const PHYSICAL_MEMORY_OFFSET: usize = KERNEL_OFFSET - PHYS_MEMORY_BASE;
|
||||
|
||||
pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024; // 8 MB
|
||||
pub const KERNEL_HEAP_SIZE: usize = 80 * 1024 * 1024; // 80 MB
|
||||
pub const STACK_PAGES_PER_HART: usize = 32;
|
||||
pub const MAX_HART_NUM: usize = 8;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use super::{boot_page_table::BootPageTable, consts::PHYSICAL_MEMORY_OFFSET};
|
||||
use super::{
|
||||
boot_page_table::BootPageTable,
|
||||
consts::{MAX_HART_NUM, PHYSICAL_MEMORY_OFFSET, STACK_PAGES_PER_HART},
|
||||
};
|
||||
use core::arch::asm;
|
||||
use device_tree::parse_smp;
|
||||
use kernel_hal::{
|
||||
|
@ -55,13 +58,15 @@ extern "C" fn primary_rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
|
|||
BOOT_PAGE_TABLE.launch(hartid)
|
||||
};
|
||||
|
||||
println!();
|
||||
println!("boot page table launched, sstatus = {sstatus:#x}");
|
||||
println!("parse device tree from {device_tree_paddr:#x}");
|
||||
let smp = parse_smp(device_tree_paddr);
|
||||
println!();
|
||||
println!(
|
||||
"
|
||||
boot page table launched, sstatus = {sstatus:#x}
|
||||
parse device tree from {device_tree_paddr:#x}
|
||||
"
|
||||
);
|
||||
|
||||
// 启动副核
|
||||
let smp = parse_smp(device_tree_paddr);
|
||||
println!("smp = {smp}");
|
||||
for id in 0..smp {
|
||||
if id != hartid {
|
||||
|
@ -106,9 +111,6 @@ extern "C" fn secondary_rust_main(hartid: usize) -> ! {
|
|||
/// 裸函数。
|
||||
#[naked]
|
||||
unsafe extern "C" fn select_stack(hartid: usize) {
|
||||
const STACK_PAGES_PER_HART: usize = 16;
|
||||
const MAX_HART_NUM: usize = 10;
|
||||
|
||||
const STACK_LEN_PER_HART: usize = 4096 * STACK_PAGES_PER_HART;
|
||||
const STACK_LEN_TOTAL: usize = STACK_LEN_PER_HART * MAX_HART_NUM;
|
||||
|
||||
|
@ -121,8 +123,8 @@ unsafe extern "C" fn select_stack(hartid: usize) {
|
|||
" li t1, {len_per_hart}",
|
||||
"1: add sp, sp, t1",
|
||||
" addi t0, t0, -1",
|
||||
" bgtz t0, 1b",
|
||||
"2: ret",
|
||||
" bnez t0, 1b",
|
||||
" ret",
|
||||
stack = sym BOOT_STACK,
|
||||
len_per_hart = const STACK_LEN_PER_HART,
|
||||
options(noreturn)
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
/* Generated by build.rs. DO NOT EDIT. */
|
||||
PROVIDE_HIDDEN(BASE_ADDRESS = 0xffffffff80200000);
|
|
@ -25,18 +25,17 @@ SECTIONS
|
|||
sdata = .;
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
}
|
||||
|
||||
. = ALIGN(4K);
|
||||
edata = .;
|
||||
|
||||
. = ALIGN(4K);
|
||||
edata = .;
|
||||
.bss : {
|
||||
bootstack = .;
|
||||
*(.bss.bootstack)
|
||||
bootstacktop = .;
|
||||
}
|
||||
|
||||
sbss = .;
|
||||
.bss : {
|
||||
. = ALIGN(4K);
|
||||
sbss = .;
|
||||
*(.bss .bss.* .sbss)
|
||||
}
|
||||
|
||||
|
|
|
@ -119,7 +119,8 @@ pub fn wait_for_exit(proc: Option<Arc<Process>>) -> ! {
|
|||
|
||||
#[cfg(not(feature = "libos"))]
|
||||
pub fn wait_for_exit(proc: Option<Arc<Process>>) -> ! {
|
||||
kernel_hal::timer::timer_set_first();
|
||||
kernel_hal::timer::timer_enable();
|
||||
info!("executor run!");
|
||||
loop {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
let has_task = executor_origin::run_until_idle();
|
||||
|
|
|
@ -1009,6 +1009,8 @@ pub const USER_ASPACE_BASE: u64 = 0;
|
|||
// pub const USER_ASPACE_BASE: u64 = 0x0000_0000_0100_0000;
|
||||
/// The size of user address space
|
||||
pub const USER_ASPACE_SIZE: u64 = (1u64 << 47) - 4096 - USER_ASPACE_BASE;
|
||||
/// The default number of user stack pages
|
||||
pub const USER_STACK_PAGES: usize = 128;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -234,15 +234,12 @@ impl Syscall<'_> {
|
|||
let mut ret: ZxResult = Ok(());
|
||||
for disposition in dispositions.iter_mut() {
|
||||
if let Ok((object, src_rights)) = proc.get_dyn_object_and_rights(disposition.handle) {
|
||||
match handle_check(disposition, &object, src_rights, handle) {
|
||||
Err(e) => {
|
||||
disposition.result = e as _;
|
||||
if ret.is_ok() {
|
||||
ret = Err(e);
|
||||
}
|
||||
if let Err(e) = handle_check(disposition, &object, src_rights, handle) {
|
||||
disposition.result = e as _;
|
||||
if ret.is_ok() {
|
||||
ret = Err(e);
|
||||
}
|
||||
Ok(()) => (),
|
||||
};
|
||||
}
|
||||
let new_rights = if disposition.rights != Rights::SAME_RIGHTS.bits() {
|
||||
Rights::from_bits(disposition.rights).unwrap()
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue