├── .github ├── dependabot.yml └── workflows │ ├── clippy.yml │ ├── documentation.yml │ ├── format.yml │ ├── rebase.yml │ ├── skylake2x-tests.yml │ ├── skylake4x-tests.yml │ └── test.yml ├── .gitignore ├── .gitmodules ├── .rustfmt.toml ├── CODE-OF-CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── NOTICE ├── README.md ├── bootloader ├── .gitignore ├── Cargo.toml ├── OVMF_CODE.fd ├── OVMF_VARS.fd ├── README.md ├── src │ ├── kernel.rs │ ├── main.rs │ ├── modules.rs │ ├── switch.S │ └── vspace.rs └── x86_64-uefi.json ├── doc ├── .gitignore ├── README.md ├── book.toml └── src │ ├── Configuration.md │ ├── Contributors.md │ ├── Development.md │ ├── Overview.md │ ├── RelatedWork.md │ ├── SUMMARY.md │ ├── architecture │ ├── Communication.md │ ├── Concurrency.md │ ├── ConcurrentNodeReplication.md │ ├── FileSystem.md │ ├── KernelArchitecture.md │ ├── Memory.md │ ├── NodeReplication.md │ ├── Process.md │ └── Scheduler.md │ ├── benchmarking │ ├── ArtifactEvaluation.md │ ├── Baselines.md │ ├── Benchmarking.md │ ├── LevelDb.md │ ├── Memcached.md │ ├── Microbenchmarks.md │ └── Redis.md │ ├── configuration │ └── CI.md │ ├── development │ ├── Building.md │ ├── Configuration.md │ ├── Debugging.md │ ├── Running.md │ ├── Styleguide.md │ ├── Testing.md │ └── Tracing.md │ ├── diagrams │ ├── AddressSpaceLayout.excalidraw │ ├── AddressSpaceLayout.png │ ├── CNROverview.excalidraw │ ├── CNROverview.png │ ├── DetMemAllocator.excalidraw │ ├── DetMemAllocator.png │ ├── FrameCacheLarge-FrameCacheSmall.excalidraw │ ├── FrameCacheLarge-FrameCacheSmall.png │ ├── LogBasedArchitecture.excalidraw │ ├── LogBasedArchitecture.png │ ├── NrFlatCombiner.excalidraw │ ├── NrFlatCombiner.png │ ├── NrLog.excalidraw │ ├── NrLog.png │ ├── NrRWLock.excalidraw │ ├── NrRWLock.png │ ├── Process.excalidraw │ ├── Process.png │ ├── Slabmalloc.excalidraw │ ├── Slabmalloc.png │ ├── advance-head.excalidraw │ ├── advance-head.png │ ├── log-memory-layout.excalidraw │ ├── log-memory-layout.png │ ├── tail-head-ctail.excalidraw │ └── tail-head-ctail.png │ ├── environment │ ├── Environment.md │ ├── cxl.md │ ├── pmem.md │ ├── rdma.md │ └── vmem.md │ └── userspace │ ├── KPI.md │ ├── Lineup.md │ ├── Memory.md │ ├── UserSpace.md │ ├── Vibrio.md │ └── rkapps.md ├── kernel ├── .cargo │ └── config ├── .gdbinit ├── Cargo.toml ├── build.rs ├── cmdline.in ├── commitable.sh ├── qemu_affinity.py ├── run.py ├── src │ ├── arch │ │ ├── unix │ │ │ ├── coreboot.rs │ │ │ ├── debug.rs │ │ │ ├── irq.rs │ │ │ ├── kcb.rs │ │ │ ├── memory.rs │ │ │ ├── mod.rs │ │ │ ├── network.rs │ │ │ ├── process.rs │ │ │ ├── rackscale.rs │ │ │ ├── signals.rs │ │ │ ├── syscalls.rs │ │ │ ├── timer.rs │ │ │ ├── tlb.rs │ │ │ └── vspace.rs │ │ └── x86_64 │ │ │ ├── acpi.rs │ │ │ ├── acpi_printf.c │ │ │ ├── acpi_printf.h │ │ │ ├── coreboot.rs │ │ │ ├── debug.rs │ │ │ ├── exec.S │ │ │ ├── gdb │ │ │ ├── breakpoints.rs │ │ │ ├── mod.rs │ │ │ ├── section_offsets.rs │ │ │ ├── serial.rs │ │ │ ├── single_register.rs │ │ │ └── single_thread_ops.rs │ │ │ ├── gdt.rs │ │ │ ├── irq.rs │ │ │ ├── isr.S │ │ │ ├── isr.rs │ │ │ ├── kcb.rs │ │ │ ├── memory.rs │ │ │ ├── mod.rs │ │ │ ├── process.rs │ │ │ ├── rackscale │ │ │ ├── client_state.rs │ │ │ ├── controller.rs │ │ │ ├── controller_state.rs │ │ │ ├── dcm │ │ │ │ ├── affinity_alloc.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── node_registration.rs │ │ │ │ ├── resource_alloc.rs │ │ │ │ └── resource_release.rs │ │ │ ├── fileops │ │ │ │ ├── close.rs │ │ │ │ ├── delete.rs │ │ │ │ ├── getinfo.rs │ │ │ │ ├── mkdir.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── open.rs │ │ │ │ ├── rename.rs │ │ │ │ └── rw.rs │ │ │ ├── get_shmem_frames.rs │ │ │ ├── get_shmem_structure.rs │ │ │ ├── kernelrpc.rs │ │ │ ├── mod.rs │ │ │ ├── processops │ │ │ │ ├── allocate_physical.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── print.rs │ │ │ │ ├── release_core.rs │ │ │ │ ├── release_physical.rs │ │ │ │ └── request_core.rs │ │ │ ├── registration.rs │ │ │ ├── syscalls.rs │ │ │ └── systemops │ │ │ │ ├── get_hardware_threads.rs │ │ │ │ └── mod.rs │ │ │ ├── serial.rs │ │ │ ├── signals.rs │ │ │ ├── start_ap.S │ │ │ ├── syscall.rs │ │ │ ├── timer.rs │ │ │ ├── tlb.rs │ │ │ ├── tls.rs │ │ │ ├── vspace │ │ │ ├── debug.rs │ │ │ ├── mod.rs │ │ │ ├── page_table.rs │ │ │ └── test.rs │ │ │ └── x86_64-nrk.json │ ├── cmdline.rs │ ├── environment.rs │ ├── error.rs │ ├── fallible_string.rs │ ├── fs │ │ ├── cnrfs.rs │ │ ├── fd.rs │ │ ├── file.rs │ │ ├── mnode.rs │ │ ├── mod.rs │ │ ├── rwlock.rs │ │ └── test.rs │ ├── graphviz.rs │ ├── integration_tests.rs │ ├── main.rs │ ├── memory │ │ ├── backends.rs │ │ ├── detmem.rs │ │ ├── emem.rs │ │ ├── frame.rs │ │ ├── global.rs │ │ ├── mcache.rs │ │ ├── mod.rs │ │ ├── per_core.rs │ │ ├── shmem_affinity.rs │ │ ├── shmemalloc.rs │ │ ├── utils.rs │ │ ├── vspace.rs │ │ └── vspace_model.rs │ ├── mpmc.rs │ ├── nr.rs │ ├── nrproc.rs │ ├── panic.rs │ ├── pci.rs │ ├── prelude.rs │ ├── process.rs │ ├── scheduler │ │ └── mod.rs │ ├── stack.rs │ ├── syscalls.rs │ └── transport │ │ ├── ethernet.rs │ │ ├── mod.rs │ │ └── shmem.rs ├── tests │ ├── dhcpd.conf │ ├── s00_core_tests.rs │ ├── s01_kernel_low_tests.rs │ ├── s02_kernel_high_tests.rs │ ├── s03_kernel_high_tests.rs │ ├── s04_user_runtime_tests.rs │ ├── s05_user_app_tests.rs │ ├── s06_rackscale_tests.rs │ ├── s10_benchmarks.rs │ └── s11_rackscale_benchmarks.rs └── testutils │ ├── Cargo.toml │ ├── build.rs │ └── src │ ├── builder.rs │ ├── helpers.rs │ ├── lib.rs │ ├── rackscale_runner.rs │ ├── redis.rs │ └── runner_args.rs ├── lib ├── apic │ ├── .gitignore │ ├── .travis.yml │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── lib.rs │ │ ├── x2apic.rs │ │ └── xapic.rs ├── bootloader_shared │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs ├── kpi │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── io.rs │ │ ├── lib.rs │ │ ├── process.rs │ │ ├── syscalls │ │ ├── io.rs │ │ ├── macros.rs │ │ ├── memory.rs │ │ ├── mod.rs │ │ ├── process.rs │ │ └── system.rs │ │ ├── system.rs │ │ ├── upcall.rs │ │ └── x86_64.rs ├── lineup │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── condvar.rs │ │ ├── lib.rs │ │ ├── mutex.rs │ │ ├── rwlock.rs │ │ ├── scheduler.rs │ │ ├── semaphore.rs │ │ ├── stack.rs │ │ ├── threads.rs │ │ ├── tls2 │ │ ├── mod.rs │ │ ├── nrk.rs │ │ └── unix.rs │ │ └── upcalls.rs ├── rpc │ ├── Cargo.toml │ ├── src │ │ ├── client.rs │ │ ├── lib.rs │ │ ├── rpc.rs │ │ ├── server.rs │ │ └── transport │ │ │ ├── mod.rs │ │ │ ├── shmem │ │ │ ├── allocator.rs │ │ │ ├── mod.rs │ │ │ ├── queue_mpmc.rs │ │ │ └── transport.rs │ │ │ └── smoltcp.rs │ └── tests │ │ └── integration-test.rs ├── vibrio │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ ├── mem.rs │ │ ├── rumprt │ │ ├── crt │ │ │ ├── error.rs │ │ │ ├── mem.rs │ │ │ ├── message_queue.rs │ │ │ ├── mod.rs │ │ │ ├── process.rs │ │ │ ├── scheduler.rs │ │ │ ├── signals.rs │ │ │ ├── tls.rs │ │ │ └── unsupported.rs │ │ ├── dev.rs │ │ ├── errno.rs │ │ ├── fs.rs │ │ ├── locking.rs │ │ ├── mod.rs │ │ ├── prt │ │ │ └── mod.rs │ │ ├── sp.rs │ │ └── threads.rs │ │ ├── upcalls.rs │ │ ├── vconsole.rs │ │ └── writer.rs └── vmxnet3 │ ├── Cargo.toml │ └── src │ ├── lib.rs │ ├── pci.rs │ ├── pvrdma │ ├── mod.rs │ ├── pagedir.rs │ ├── pci.rs │ └── verbs.rs │ ├── reg.rs │ ├── smoltcp.rs │ ├── var.rs │ └── vmx.rs ├── rust-toolchain ├── scripts ├── Dockerfile ├── ci.bash ├── docker-entrypoint.sh ├── docker-run.sh ├── docker-setup.sh └── generic-setup.sh ├── setup.sh └── usr ├── init ├── Cargo.toml ├── README.md ├── build.rs └── src │ ├── fs.rs │ ├── fxmark │ ├── drbh.rs │ ├── drbl.rs │ ├── dwol.rs │ ├── dwom.rs │ ├── mix.rs │ ├── mod.rs │ ├── mwrl.rs │ └── mwrm.rs │ ├── histogram.rs │ ├── init.rs │ ├── memhash │ └── mod.rs │ ├── tests.rs │ └── vmops │ ├── mod.rs │ ├── queue.rs │ └── unmaplat.rs ├── rkapps ├── Cargo.toml ├── README.md ├── build.rs └── src │ └── main.rs └── x86_64-nrk-none.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # See 2 | # https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/enabling-and-disabling-version-updates 3 | # for details 4 | 5 | version: 2 6 | updates: 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "daily" 11 | - package-ecosystem: "cargo" 12 | directory: "/kernel" 13 | schedule: 14 | interval: "daily" 15 | - package-ecosystem: "cargo" 16 | directory: "/bootloader" 17 | schedule: 18 | interval: "daily" 19 | - package-ecosystem: "cargo" 20 | directory: "/lib/bootloader_shared" 21 | schedule: 22 | interval: "daily" 23 | - package-ecosystem: "cargo" 24 | directory: "/lib/kpi" 25 | schedule: 26 | interval: "daily" 27 | - package-ecosystem: "cargo" 28 | directory: "/lib/lineup" 29 | schedule: 30 | interval: "daily" 31 | - package-ecosystem: "cargo" 32 | directory: "/lib/vibrio" 33 | schedule: 34 | interval: "daily" 35 | - package-ecosystem: "cargo" 36 | directory: "/lib/vmxnet3" 37 | schedule: 38 | interval: "daily" -------------------------------------------------------------------------------- /.github/workflows/clippy.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches-ignore: 4 | - 'dependabot/**' 5 | paths-ignore: 6 | - 'doc/**' 7 | - '**.md' 8 | 9 | name: Run clippy 10 | jobs: 11 | clippy_check: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3.0.2 15 | - run: | 16 | sed -i'' -e 's/git@github.com:/https:\/\/github.com\//' .gitmodules 17 | git submodule update --init 18 | rustup show 19 | - uses: actions/cache@v3 20 | with: 21 | path: | 22 | ~/.cargo/bin/ 23 | ~/.cargo/registry/index/ 24 | ~/.cargo/registry/cache/ 25 | ~/.cargo/git/db/ 26 | target/ 27 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 28 | - uses: actions-rs/clippy-check@v1 29 | with: 30 | token: ${{ secrets.GITHUB_TOKEN }} 31 | args: --package nrk -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | paths: 6 | - doc/** 7 | - .github/** 8 | 9 | name: Deploy documentation 10 | jobs: 11 | deploy_docs: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3.0.2 15 | - name: Checkout website repository 16 | uses: actions/checkout@v3.0.2 17 | with: 18 | repository: gz/bespin-benchmarks 19 | path: gh-pages 20 | ssh-key: ${{ secrets.WEBSITE_DEPLOY_SSH_KEY }} 21 | - run: | 22 | source ~/.cargo/env 23 | cargo install mdbook --locked --no-default-features --features search 24 | cd doc 25 | mdbook build -d ../book 26 | cd .. 27 | cd gh-pages 28 | rm -rf ./book 29 | mv ../book ./ 30 | git config user.name bespin-ci 31 | git config user.email noreply@nrkernel.systems 32 | git add . 33 | git commit -a -m "Added documentation." || true 34 | git push origin master || true 35 | cd .. 36 | rm -rf gh-pages/ book/ 37 | -------------------------------------------------------------------------------- /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | paths-ignore: 4 | - 'doc/**' 5 | - '**.md' 6 | pull_request: 7 | paths-ignore: 8 | - 'doc/**' 9 | - '**.md' 10 | types: [opened, review_requested, reopened] 11 | 12 | name: Check Formatting 13 | jobs: 14 | formatting: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3.0.2 18 | - run: | 19 | sed -i'' -e 's/git@github.com:/https:\/\/github.com\//' .gitmodules 20 | git submodule update --init 21 | rustup show 22 | - uses: actions/cache@v3 23 | with: 24 | path: | 25 | ~/.cargo/bin/ 26 | ~/.cargo/registry/index/ 27 | ~/.cargo/registry/cache/ 28 | ~/.cargo/git/db/ 29 | target/ 30 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 31 | - name: Run cargo fmt 32 | run: cargo fmt -- --check -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | name: Automatic Rebase 2 | on: 3 | issue_comment: 4 | types: [created] 5 | jobs: 6 | rebase: 7 | name: Rebase 8 | if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout the latest code 12 | uses: actions/checkout@v3.0.2 13 | with: 14 | token: ${{ secrets.GITHUB_TOKEN }} 15 | fetch-depth: 0 # otherwise, you will fail to push refs to dest repo 16 | - name: Automatic Rebase 17 | uses: cirrus-actions/rebase@1.5 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/skylake2x-tests.yml: -------------------------------------------------------------------------------- 1 | on: [push] 2 | 3 | defaults: 4 | run: 5 | shell: bash 6 | 7 | name: Integration tests (skylake2x) 8 | jobs: 9 | pre_job: 10 | runs-on: ubuntu-latest 11 | outputs: 12 | should_skip: ${{ steps.skip_check.outputs.should_skip }} 13 | steps: 14 | - id: skip_check 15 | uses: fkirc/skip-duplicate-actions@master 16 | with: 17 | concurrent_skipping: 'never' 18 | skip_after_successful_duplicate: 'true' 19 | paths_ignore: '["**/README.md", "**/doc/**"]' 20 | do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' 21 | test-skylake2x: 22 | needs: pre_job 23 | if: ${{ needs.pre_job.outputs.should_skip != 'true' }} 24 | runs-on: [self-hosted, skylake2x] 25 | steps: 26 | - uses: actions/checkout@v3.0.2 27 | - run: | 28 | sed -i'' -e 's/git@github.com:/https:\/\/github.com\//' .gitmodules 29 | git submodule update --init 30 | rustup show 31 | - name: Integration tests (qemu/kvm) 32 | run: | 33 | bash setup.sh 34 | cd kernel 35 | RUST_TEST_THREADS=1 cargo test --features smoke 36 | bench-skylake2x: 37 | needs: [pre_job, test-skylake2x] 38 | if: ${{ needs.pre_job.outputs.should_skip != 'true' }} 39 | runs-on: [self-hosted, skylake2x] 40 | steps: 41 | - uses: actions/checkout@v3.0.2 42 | - run: | 43 | sed -i'' -e 's/git@github.com:/https:\/\/github.com\//' .gitmodules 44 | git submodule update --init 45 | rustup show 46 | - name: Run Benchmarks 47 | run: | 48 | bash setup.sh 49 | bash scripts/ci.bash 50 | env: 51 | CI_MACHINE_TYPE: "skylake2x" 52 | -------------------------------------------------------------------------------- /.github/workflows/skylake4x-tests.yml: -------------------------------------------------------------------------------- 1 | on: [push] 2 | 3 | defaults: 4 | run: 5 | shell: bash 6 | 7 | name: Integration tests (skylake4x) 8 | jobs: 9 | pre_job: 10 | runs-on: ubuntu-latest 11 | outputs: 12 | should_skip: ${{ steps.skip_check.outputs.should_skip }} 13 | steps: 14 | - id: skip_check 15 | uses: fkirc/skip-duplicate-actions@master 16 | with: 17 | concurrent_skipping: 'never' 18 | skip_after_successful_duplicate: 'true' 19 | paths_ignore: '["**/README.md", "**/doc/**"]' 20 | do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' 21 | test-skylake4x: 22 | needs: pre_job 23 | if: ${{ needs.pre_job.outputs.should_skip != 'true' }} 24 | runs-on: [self-hosted, skylake4x] 25 | steps: 26 | - uses: actions/checkout@v3.0.2 27 | - run: | 28 | sed -i'' -e 's/git@github.com:/https:\/\/github.com\//' .gitmodules 29 | git submodule update --init 30 | rustup show 31 | - name: Integration tests (qemu/kvm) 32 | run: | 33 | bash setup.sh 34 | cd kernel 35 | RUST_TEST_THREADS=1 cargo test --features smoke 36 | bench-skylake4x: 37 | needs: [pre_job, test-skylake4x] 38 | if: ${{ needs.pre_job.outputs.should_skip != 'true' }} 39 | runs-on: [self-hosted, skylake4x] 40 | steps: 41 | - uses: actions/checkout@v3.0.2 42 | - run: | 43 | sed -i'' -e 's/git@github.com:/https:\/\/github.com\//' .gitmodules 44 | git submodule update --init 45 | rustup show 46 | - name: Run Benchmarks 47 | run: | 48 | bash setup.sh 49 | bash scripts/ci.bash 50 | env: 51 | CI_MACHINE_TYPE: "skylake4x" -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # If you modify this file, also ensure that the change/addition is reflected in `commitable.sh`. 2 | on: 3 | push: 4 | paths-ignore: 5 | - 'doc/**' 6 | - '**.md' 7 | pull_request: 8 | paths-ignore: 9 | - 'doc/**' 10 | - '**.md' 11 | types: [opened, review_requested, reopened] 12 | 13 | name: Compile and run unit tests 14 | jobs: 15 | compile_and_test: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v3.0.2 19 | - run: | 20 | sed -i'' -e 's/git@github.com:/https:\/\/github.com\//' .gitmodules 21 | git submodule update --init 22 | rustup show 23 | #- uses: Swatinem/rust-cache@v1 24 | - run: | 25 | bash setup.sh 26 | - name: Compile check (x86_64-nrk) 27 | run: python3 run.py --norun 28 | working-directory: ./kernel 29 | - name: Compile check (unix) 30 | run: cargo run 31 | working-directory: ./kernel 32 | - name: Kernel unit tests 33 | run: RUST_TEST_THREADS=1 cargo test --features smoke --bin nrk 34 | working-directory: ./kernel 35 | - name: apic tests 36 | run: cargo test --all-features 37 | working-directory: ./lib/apic 38 | - name: bootloader_shared tests 39 | run: cargo test --all-features 40 | working-directory: ./lib/bootloader_shared 41 | - name: kpi tests 42 | run: cargo test --all-features 43 | working-directory: ./lib/kpi 44 | # Disabled at the moment, need to fix the flaky tests: 45 | #- name: lineup tests 46 | # run: RUST_TEST_THREADS=1 cargo test 47 | # working-directory: ./lib/lineup 48 | - name: vibrio tests 49 | run: cargo test --all-features 50 | working-directory: ./lib/vibrio 51 | - name: vmxnet3 tests 52 | run: cargo test --all-features 53 | working-directory: ./lib/vmxnet3 54 | - name: RPC tests 55 | run: cargo test --all-features 56 | working-directory: ./lib/rpc 57 | - name: Build the documentation 58 | run: mdbook build 59 | working-directory: ./doc/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries 2 | kernel.bin* 3 | *.o 4 | *.rlib 5 | kernel/nrk 6 | kernel/kernel 7 | kernel/uefi.img 8 | ivshmem-file 9 | 10 | # rump 11 | rump/binutils-2.30.90 12 | rump/gcc-8.2.0 13 | gcc-8.2.0.tar.gz 14 | 15 | # Builds 16 | target/ 17 | 18 | # Editor configs 19 | .vscode 20 | .tmuxinator.yml 21 | 22 | binutils-* 23 | public 24 | .gdb_history 25 | .DS_Store 26 | 27 | # Build/test artefacts 28 | proptest-regressions 29 | **/*.csv 30 | vspace.dot 31 | vspace.dot.svg 32 | out.log 33 | *.pdf 34 | *.png 35 | *.img 36 | *.iso 37 | dcm.log 38 | 39 | # RLS logs 40 | rls*.log 41 | 42 | # Random notes 43 | *NOTES* 44 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/node-replication"] 2 | path = lib/node-replication 3 | branch = mut_scan_vec 4 | url = git@github.com:gz/node-replication.git 5 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 100 2 | hard_tabs = false 3 | tab_spaces = 4 4 | newline_style = "Auto" 5 | use_small_heuristics = "Default" 6 | indent_style = "Block" 7 | wrap_comments = false 8 | format_code_in_doc_comments = false 9 | comment_width = 80 10 | normalize_comments = false 11 | normalize_doc_attributes = false 12 | format_strings = false 13 | format_macro_matchers = false 14 | format_macro_bodies = true 15 | empty_item_single_line = true 16 | struct_lit_single_line = true 17 | fn_single_line = false 18 | where_single_line = false 19 | imports_indent = "Block" 20 | imports_layout = "Mixed" 21 | imports_granularity = "Preserve" 22 | group_imports = "Preserve" 23 | reorder_imports = true 24 | reorder_modules = true 25 | reorder_impl_items = false 26 | type_punctuation_density = "Wide" 27 | space_before_colon = false 28 | space_after_colon = true 29 | spaces_around_ranges = false 30 | binop_separator = "Front" 31 | remove_nested_parens = true 32 | combine_control_expr = true 33 | overflow_delimited_expr = false 34 | struct_field_align_threshold = 0 35 | enum_discrim_align_threshold = 0 36 | match_arm_blocks = true 37 | match_arm_leading_pipes = "Never" 38 | force_multiline_blocks = false 39 | fn_args_layout = "Tall" 40 | brace_style = "SameLineWhere" 41 | control_brace_style = "AlwaysSameLine" 42 | trailing_semicolon = true 43 | trailing_comma = "Vertical" 44 | match_block_trailing_comma = false 45 | blank_lines_upper_bound = 1 46 | blank_lines_lower_bound = 0 47 | edition = "2015" 48 | version = "One" 49 | inline_attribute_width = 0 50 | merge_derives = true 51 | use_try_shorthand = false 52 | use_field_init_shorthand = false 53 | force_explicit_abi = true 54 | condense_wildcard_suffixes = false 55 | color = "Auto" 56 | required_version = "1.5.1" 57 | unstable_features = false 58 | disable_all_formatting = false 59 | skip_children = false 60 | hide_parse_errors = false 61 | error_on_line_overflow = false 62 | error_on_unformatted = false 63 | ignore = [] 64 | emit_mode = "Files" 65 | make_backup = false 66 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to node-replicated-kernel 2 | 3 | The node-replicted-kernel project team welcomes contributions from the community. If 4 | you wish to contribute code and you have not signed our contributor license 5 | agreement (CLA), our bot will update the issue when you open a Pull Request. For 6 | any questions about the CLA process, please refer to our 7 | [FAQ](https://cla.vmware.com/faq). 8 | 9 | ## Contribution Flow 10 | 11 | This is a rough outline of what a contributor's workflow looks like: 12 | 13 | - Create a topic branch from where you want to base your work 14 | - Make commits of logical units 15 | - Make sure your commit messages are in the proper format (see below) 16 | - Push your changes to a topic branch in your fork of the repository 17 | - Test changes locally 18 | - Submit a pull request 19 | 20 | Example: 21 | 22 | Update latest master: 23 | 24 | 1. `git checkout master` 25 | 1. `git pull` 26 | 1. `git submodule update --init` 27 | 28 | Create a new feature branch: 29 | 30 | 1. `git checkout -b ` 31 | 1. Make changes in code. 32 | 33 | Make sure that the code compiles without warnings, is properly formatted and passes tests: 34 | 35 | 1. `cd kernel` 36 | 1. `bash commitable.sh` 37 | 38 | Commit changes and push 39 | 40 | 1. `git add ` 41 | 1. `git commit` 42 | 1. `git push -u origin ` 43 | 1. Create a Pull Request on GitHub. 44 | 45 | ### Updating pull requests 46 | 47 | If your PR fails to pass CI or needs changes based on code review, you'll most likely want to squash these changes into 48 | existing commits. 49 | 50 | If your pull request contains a single commit or your changes are related to the most recent commit, you can simply 51 | amend the commit. 52 | 53 | ``` shell 54 | git add . 55 | git commit --amend 56 | git push --force-with-lease origin my-new-feature 57 | ``` 58 | 59 | If you need to squash changes into an earlier commit, you can use: 60 | 61 | ``` shell 62 | git add . 63 | git commit --fixup 64 | git rebase -i --autosquash master 65 | git push --force-with-lease origin my-new-feature 66 | ``` 67 | 68 | Be sure to add a comment to the PR indicating your new changes are ready to review, as GitHub does not generate a 69 | notification when you git push. 70 | 71 | ### Code Style 72 | 73 | Be sure to follow the [style-guide](doc/src/development/Styleguide.md). 74 | 75 | ## Reporting Bugs and Creating Issues 76 | 77 | When opening a new issue, try to roughly follow the commit message format conventions above. 78 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | 4 | members = [ 5 | "bootloader", 6 | "kernel", 7 | "lib/apic", 8 | "lib/bootloader_shared", 9 | "lib/kpi", 10 | "lib/lineup", 11 | "lib/node-replication/cnr", 12 | "lib/node-replication/nr", 13 | "lib/rpc", 14 | "lib/vibrio", 15 | "lib/vmxnet3", 16 | "lib/rpc", 17 | "usr/init", 18 | "usr/rkapps", 19 | #"lib/fallible_collections", 20 | #"lib/libfringe", 21 | #"lib/acpica-sys" 22 | #"lib/rust-topology", 23 | #"lib/rust-driverkit", 24 | #"lib/rust-armv8", 25 | #"lib/rust-x86", 26 | #"lib/rawtime", 27 | #"lib/backtracer", 28 | #"lib/rust-klogger", 29 | #"lib/rexpect", 30 | #"lib/pl011_qemu", 31 | ] 32 | 33 | # disable stack unwinding on panic for now 34 | [profile.dev] 35 | panic = "abort" 36 | debug = true 37 | 38 | [profile.release] 39 | panic = "abort" 40 | debug = true 41 | 42 | [patch.crates-io] 43 | #x86 = { path = "lib/rust-x86" } 44 | #driverkit = { path = "lib/rust-driverkit" } 45 | #rawtime = { path = "lib/rawtime" } 46 | #atopology = { path = "lib/rust-topology" } 47 | #klogger = { path = "lib/rust-klogger" } 48 | #libacpica = { path = "lib/acpica-sys" } 49 | #rexpect = { path = "lib/rexpect" } 50 | #backtracer_core = { path = "lib/backtracer" } -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT license (the "License") set forth below applies to all parts of the 2 | node-replication project. You may not use this file except in compliance with 3 | the License. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node Replicated Kernel 2 | 3 | The Node Replicated Kernel is an (experimental) research OS kernel for x86-64 4 | (amd64) machines written in rust. You can read more about it 5 | [here](https://nrkernel.systems/book/). 6 | 7 | ## Installation 8 | 9 | ### Check-out the source tree 10 | 11 | 1. `git clone nrk` 12 | 1. `cd nrk` 13 | 1. Note: In case you don't have the SSH key of your machine registered with a github account, 14 | you need to convert the submodule URLs to the https protocol, to do so run: 15 | `sed -i'' -e 's/git@github.com:/https:\/\/github.com\//' .gitmodules` 16 | 1. `git submodule update --init` 17 | 18 | ### Install dependencies 19 | 20 | Run `bash setup.sh`, this will install required dependencies on Linux to build and run nrk. 21 | 22 | ### Build and run 23 | 24 | 1. `cd kernel` 25 | 1. `python3 ./run.py` 26 | 27 | If you just want to compile the code you can also execute `run.py` with the 28 | `--norun` flag. 29 | 30 | ## Development 31 | 32 | ### Testing 33 | 34 | To run the unit tests of the kernel: 35 | 36 | 1. `cd kernel` 37 | 1. `RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --bin nrk` 38 | 39 | To run the integration tests of the kernel: 40 | 41 | 1. `cd kernel` 42 | 1. `RUST_TEST_THREADS=1 cargo test --features smoke --test integration-test` 43 | 44 | If you would like to run a specific integration test you can pass it with `--`: 45 | 46 | 1. `RUST_TEST_THREADS=1 cargo test --test integration-test -- --nocapture userspace_smoke` 47 | 48 | > Note: Parallel testing is not possible at the moment due to reliance on build flags for testing. 49 | 50 | ### Submitting a change 51 | 52 | Update latest master: 53 | 54 | 1. `git checkout master` 55 | 1. `git pull` 56 | 1. `git submodule update --init` 57 | 58 | Create a new feature branch: 59 | 60 | 1. `git checkout -b ` 61 | 1. Make changes in code. 62 | 63 | Make sure that the code compiles without warnings, is properly formatted and passes tests: 64 | 65 | 1. `cd kernel` 66 | 1. `bash commitable.sh` 67 | 68 | Commit changes and push 69 | 70 | 1. `git add ` 71 | 1. `git commit` 72 | 1. `git push -u origin ` 73 | 1. Create a Pull Request on GitHub. 74 | -------------------------------------------------------------------------------- /bootloader/.gitignore: -------------------------------------------------------------------------------- 1 | # Python cache files. 2 | /__pycache__ 3 | 4 | # OVMF images, which provide a UEFI firmware for QEMU. 5 | /OVMF_CODE.fd 6 | /OVMF_VARS.fd 7 | -------------------------------------------------------------------------------- /bootloader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bootloader" 3 | version = "0.0.1" 4 | authors = ["Gerd Zellweger "] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | resolver = "2" 8 | 9 | [features] 10 | default = [] 11 | 12 | [dependencies] 13 | ## Internal dependencies 14 | bootloader_shared = { path = "../lib/bootloader_shared" } 15 | 16 | ## External dependencies 17 | x86 = { version = "0.52", features = ["unstable"] } 18 | elfloader = "0.14" 19 | log = { version = "0.4", default-features = false } 20 | arrayvec = { version = "0.7.0", default-features = false } 21 | uefi = { version = "0.15", features = ["exts"] } 22 | uefi-services = "0.12" -------------------------------------------------------------------------------- /bootloader/OVMF_CODE.fd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/bootloader/OVMF_CODE.fd -------------------------------------------------------------------------------- /bootloader/OVMF_VARS.fd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/bootloader/OVMF_VARS.fd -------------------------------------------------------------------------------- /bootloader/README.md: -------------------------------------------------------------------------------- 1 | # bootloader 2 | 3 | This is a UEFI based bootloader that does some minimal hardware initialization, 4 | loads a position-independent, x86-64 ELF kernel and then jumps to the kernel. -------------------------------------------------------------------------------- /bootloader/src/switch.S: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | // UEFI uses Windows calling convention: 5 | // ARG1 %rcx 6 | // ARG2 %rdx 7 | // ARG3 %r8 8 | 9 | .text 10 | .extern jump_to_kernel 11 | jump_to_kernel: // fn(stack_ptr: u64, kernel_entry: u64, kernel_arg: u64) 12 | // switch to our new stack 13 | mov %rcx, %rbp 14 | mov %rcx, %rsp 15 | // move the data pointer to the first argument 16 | // kernel expects sysv64 calling convention so rdi becomes first arg 17 | mov %r8, %rdi 18 | 19 | // We push 0 as return address in case we do stack backtracing we can 20 | // abort 21 | pushq $0 22 | 23 | // absolute jump rather than call to the kernel entry point 24 | jmp *%rdx 25 | never_return: 26 | hlt 27 | jmp never_return 28 | -------------------------------------------------------------------------------- /bootloader/x86_64-uefi.json: -------------------------------------------------------------------------------- 1 | { 2 | "llvm-target": "x86_64-pc-windows-gnu", 3 | "env": "gnu", 4 | "target-family": "windows", 5 | "target-endian": "little", 6 | "target-pointer-width": "64", 7 | "target-c-int-width": "32", 8 | "os": "uefi", 9 | "arch": "x86_64", 10 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", 11 | "linker": "rust-lld", 12 | "linker-flavor": "lld-link", 13 | "pre-link-args": { 14 | "lld-link": [ 15 | "/Subsystem:EFI_Application", 16 | "/Entry:uefi_start" 17 | ] 18 | }, 19 | "panic-strategy": "abort", 20 | "default-hidden-visibility": true, 21 | "executables": true, 22 | "position-independent-executables": true, 23 | "exe-suffix": ".efi", 24 | "is-like-windows": true, 25 | "emit-debug-gdb-scripts": false 26 | } 27 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | The documentation can be compiled using 4 | [mdbook](https://github.com/rust-lang/mdBook) and viewed with a browser. 5 | 6 | To build and access the docs locally, execute: 7 | 8 | ```bash 9 | mdbook serve 10 | ``` 11 | 12 | To install mdbook, run: 13 | 14 | ```bash 15 | cargo install mdbook 16 | ``` 17 | 18 | The most current HEAD of the master branch is [available 19 | online](https://nrkernel.systems/book/). 20 | -------------------------------------------------------------------------------- /doc/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Gerd Zellweger"] 3 | multilingual = false 4 | src = "src" 5 | title = "nrk Documentation" 6 | description = "NRK Developer Handbook" 7 | language = "en" 8 | 9 | [rust] 10 | edition = "2018" 11 | 12 | [output.html] 13 | git-repository-url = "https://github.com/vmware-labs/node-replicated-kernel/tree/master/doc" 14 | 15 | [output.html.search] 16 | limit-results = 20 17 | use-boolean-and = true 18 | boost-title = 2 19 | boost-hierarchy = 2 20 | boost-paragraph = 1 21 | expand = true 22 | heading-split-level = 2 -------------------------------------------------------------------------------- /doc/src/Configuration.md: -------------------------------------------------------------------------------- 1 | # Setup & Configuration 2 | -------------------------------------------------------------------------------- /doc/src/Contributors.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | Here is a list of the contributors who helped to build NRK. Big shout-out to them! 4 | 5 | - [Amy Tai](https://amytai.github.io/) 6 | - [Ankit Bhardwaj](https://ankitbhrdwj.github.io/) 7 | - [Chinmay Kulkarni](https://www.chinmayk.net/) 8 | - [Christian Menges](https://github.com/Garfield96/) 9 | - [Erika Hunhoff](https://hunhoffe.github.io/) 10 | - [Gerd Zellweger](https://gerdzellweger.com/) 11 | - [Irina Calciu](https://icalciu.github.io/) 12 | - [Reto Achermann](https://retoachermann.ch/) 13 | - [Ryan Stutsman](https://rstutsman.github.io/) 14 | - [Sanidhya Kashyap](https://sanidhya.github.io/) 15 | - [Stanko Novakovic](https://www.microsoft.com/en-us/research/people/stnovako/) 16 | - [Zack McKevitt](https://zackmckevitt.com/) 17 | 18 | If you feel you're missing from this list, feel free to add yourself in a PR. 19 | -------------------------------------------------------------------------------- /doc/src/Development.md: -------------------------------------------------------------------------------- 1 | # Development 2 | 3 | This chapter should teach you how to [Build](./development/Building.md), 4 | [Run](./development/Running.md), [Debug](./development/Debugging.md), 5 | [Test](./development/Testing.md) and [Trace](./development/Tracing.md) the OS. -------------------------------------------------------------------------------- /doc/src/RelatedWork.md: -------------------------------------------------------------------------------- 1 | # Related Work 2 | 3 | NRK takes inspiration from decades of academic research. The following list is 4 | by no means exhaustive: 5 | 6 | ## Operating Systems 7 | 8 | * [Barrelfish](http://www.barrelfish.org/) 9 | * [Tornado](https://www.usenix.org/legacy/events/osdi99/full_papers/gamsa/gamsa.pdf) 10 | * [K42](https://dl.acm.org/doi/10.1145/1218063.1217949) 11 | * [sv6](https://github.com/aclements/sv6) 12 | * [Rumpkernel](https://github.com/rumpkernel) 13 | * [LibrettOS](https://librettos.org/) 14 | * [seL4](https://sel4.systems/) 15 | * [Disco](https://dl.acm.org/doi/10.1145/265924.265930) 16 | * [Mitosis](https://dl.acm.org/doi/abs/10.1145/3373376.3378468) 17 | 18 | ## Scalable Data structures 19 | 20 | * [Flat combining](https://dl.acm.org/doi/10.1145/1810479.1810540) 21 | * [Read-Log-Update](https://dl.acm.org/doi/10.1145/2815400.2815406) and [RLU with multi-versioning](https://dl.acm.org/doi/10.1145/3297858.3304040) 22 | * [Predictive Log Synchronization](https://dl.acm.org/doi/10.1145/1218063.1217965) 23 | * [OpLog](http://hdl.handle.net/1721.1/89653) 24 | 25 | ## Log based designs 26 | 27 | * [ScaleFS](https://github.com/mit-pdos/scalefs) 28 | * [Corfu](https://github.com/CorfuDB/CorfuDB) 29 | * [Raft](https://raft.github.io/) 30 | -------------------------------------------------------------------------------- /doc/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Overview](./Overview.md) 4 | - [Kernel Architecture](./architecture/KernelArchitecture.md) 5 | - [Concurrency](./architecture/NodeReplication.md) 6 | - [Node Replication](./architecture/NodeReplication.md) 7 | - [Concurrent Node Replication](./architecture/ConcurrentNodeReplication.md) 8 | - [Memory](./architecture/Memory.md) 9 | - [Process](./architecture/Process.md) 10 | - [Scheduler](./architecture/Scheduler.md) 11 | - [File system](./architecture/FileSystem.md) 12 | - [User Space](./userspace/UserSpace.md) 13 | - [KPI](./userspace/KPI.md) 14 | - [Lineup](./userspace/Lineup.md) 15 | - [Vibrio](./userspace/Vibrio.md) 16 | - [RKApps](./userspace/rkapps.md) 17 | - [Development](./Development.md) 18 | - [Configuration](./development/Configuration.md) 19 | - [Styleguide](./development/Styleguide.md) 20 | - [Building](./development/Building.md) 21 | - [Running](./development/Running.md) 22 | - [Debugging](./development/Debugging.md) 23 | - [Testing](./development/Testing.md) 24 | - [Tracing](./development/Tracing.md) 25 | - [Benchmarking](./benchmarking/Benchmarking.md) 26 | - [Microbenchmarks](./benchmarking/Microbenchmarks.md) 27 | - [Redis](./benchmarking/Redis.md) 28 | - [Memcached](./benchmarking/Memcached.md) 29 | - [LevelDB](./benchmarking/LevelDb.md) 30 | - [Artifact Evaluation (OSDI'21)](./benchmarking/ArtifactEvaluation.md) 31 | - [Baselines](./benchmarking/Baselines.md) 32 | - [Environment](./environment/Environment.md) 33 | - [Persistent Memory](./environment/pmem.md) 34 | - [Remote DMA](./environment/rdma.md) 35 | - [VM shared memory](./environment/vmem.md) 36 | - [Compute Express Link](./environment/cxl.md) 37 | - [Continuous Integration](./configuration/CI.md) 38 | - [Related Work](./RelatedWork.md) 39 | 40 | ----------- 41 | 42 | - [Contributors](./Contributors.md) 43 | -------------------------------------------------------------------------------- /doc/src/architecture/Communication.md: -------------------------------------------------------------------------------- 1 | # Network 2 | 3 | Applications are pr using the network {{system}} -------------------------------------------------------------------------------- /doc/src/architecture/Concurrency.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/architecture/Concurrency.md -------------------------------------------------------------------------------- /doc/src/architecture/FileSystem.md: -------------------------------------------------------------------------------- 1 | # File System 2 | 3 | The NrFS is a simple, in-memory file system in nrk that supports some POSIX file 4 | operations (`open`, `pread`, `pwrite`, `close`, *etc.*). 5 | 6 | NrFS tracks files and directories by mapping each path to an inode number and 7 | then mapping each inode number to an in-memory inode. Each inode holds either 8 | directory or file metadata and a list of file pages. The entire data structure 9 | is wrapped by CNR for concurrent access and replication. -------------------------------------------------------------------------------- /doc/src/architecture/KernelArchitecture.md: -------------------------------------------------------------------------------- 1 | # Kernel Architecture 2 | 3 | The NRK kernel is a small, light-weight (multi-)kernel that provides a 4 | [process abstraction with virtual memory](Process.md), a [coarse-grained 5 | scheduler](Scheduler.md), as well as an [in-memory file-system](Filesystem.md). 6 | 7 | One key feature of the kernel is how it scales to many cores (and NUMA 8 | nodes) by relying on data-structure replication with operation logging. We 9 | explain the two main techniques we use for this in the [Node 10 | Replication](NodeReplication.md) and [Concurrent Node 11 | Replication](ConcurrentNodeReplication.md) sections of this chapter. 12 | -------------------------------------------------------------------------------- /doc/src/architecture/Scheduler.md: -------------------------------------------------------------------------------- 1 | # Scheduler 2 | 3 | In NRK, the kernel-level scheduler is a coarse-grained scheduler that allocates 4 | CPUs to processes. Processes make system calls to request for more cores and to 5 | give them up. The kernel notifies processes core allocations and deallocations 6 | via upcalls. To run on a core, a process allocates executor objects (*i.e.,* the 7 | equivalent of a "kernel" thread) that are used to dispatch a given process on 8 | a CPU. An executor mainly consists of two userspace stacks (one for the upcall 9 | handler and one for the initial stack) and a region to save CPU registers and 10 | other metadata. Executors are allocated lazily but a process keeps a per-NUMA 11 | node cache to reuse them over time. 12 | 13 | In the process, a userspace scheduler reacts to upcalls indicating the addition 14 | or removal of a core, and it makes fine-grained scheduling decisions by 15 | dispatching threads accordingly. This design means that the kernel is only 16 | responsible for coarse-grained scheduling decisions, and it implements a global 17 | policy of core allocation to processes. 18 | 19 | The scheduler uses a sequential hash table wrapped with NR to map each process 20 | id to a process structure and to map process executors to cores. It has 21 | operations to create or destroy a process; to allocate and deallocate executors 22 | for a process; and to obtain an executor for a given core. 23 | -------------------------------------------------------------------------------- /doc/src/benchmarking/Baselines.md: -------------------------------------------------------------------------------- 1 | # Baseline Operating Systems 2 | 3 | Contains steps to get other operating systems compiled and running for 4 | comparison purposes. 5 | 6 | ## Compare against Linux 7 | 8 | To get an idea if nrk is competitive with Linux performance we can create a 9 | Linux VM by creating an image. The following steps create an 10 | `ubuntu-testing.img` disk-image by using the ubuntu-minimal installer: 11 | 12 | ```bash 13 | wget http://archive.ubuntu.com/ubuntu/dists/bionic/main/installer-amd64/current/images/netboot/mini.iso 14 | qemu-img create -f vmdk -o size=20G ubuntu-testing.img 15 | kvm -m 2048 -k en-us --smp 2 --cpu host -cdrom mini.iso -hdd ubuntu-testing.img 16 | # Follow installer instructions 17 | ``` 18 | 19 | Afterwards the image can be booted using `kvm`: 20 | 21 | ```bash 22 | kvm -m 2048 -k en-us --smp 2 -boot d ubuntu-testing.img 23 | ``` 24 | 25 | ### Switch to serial output 26 | 27 | One step that makes life easier is to enable to serial input/output. So we don't 28 | have to use a graphical QEMU interface. To enable serial, edit the grub 29 | configuration (/etc/default/grub) as follows in the VM: 30 | 31 | ```cfg 32 | GRUB_CMDLINE_LINUX_DEFAULT="" 33 | GRUB_TERMINAL='serial console' 34 | GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0,115200n8" 35 | GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1" 36 | ``` 37 | 38 | Then you must run `update-grub` to update the menu entries. From now on, you can 39 | boot the VM using (not the `-nographic` option): 40 | 41 | ```bash 42 | qemu-system-x86_64 --enable-kvm -m 2048 -k en-us --smp 2 -boot d ubuntu-testing.img -nographic 43 | ``` 44 | 45 | ## Compare against Barrelfish 46 | 47 | TBD. 48 | 49 | ## Compare against sv6 50 | 51 | To clone & build the code (needs an older compiler version): 52 | 53 | ```bash 54 | git clone https://github.com/aclements/sv6.git 55 | sudo apt-get install gcc-4.8 g++-4.8 56 | CXX=g++-4.8 CC=gcc-4.8 make 57 | ``` 58 | 59 | Update `param.h`: 60 | 61 | ```bash 62 | QEMU ?= qemu-system-x86_64 -enable-kvm 63 | QEMUSMP ?= 56 64 | QEMUMEM ?= 24000 65 | ``` 66 | 67 | Run: 68 | 69 | ```bash 70 | CXX=g++-4.8 CC=gcc-4.8 make qemu` 71 | ``` 72 | 73 | # Rackscale 74 | 75 | One of the baselines for rackscale is NrOS. To run the rackscale benchmarks with corresponding NrOS baslines, run them with ```--feature baseline```. 76 | -------------------------------------------------------------------------------- /doc/src/benchmarking/Benchmarking.md: -------------------------------------------------------------------------------- 1 | # Benchmarking 2 | 3 | This chapter provides notes and pointers on how to set-up and run applications 4 | for benchmarking and run various OS micro-benchmarks. -------------------------------------------------------------------------------- /doc/src/benchmarking/Memcached.md: -------------------------------------------------------------------------------- 1 | # Benchmarking Memcached 2 | 3 | Yet another key--value store written in C, but compared to [Redis](./Redis.html) 4 | this one is multi-threaded. 5 | 6 | ## Automated integration test 7 | 8 | The easiest way to run memcached on nrk, is to invoke the integration test 9 | directly: 10 | 11 | ```bash 12 | cd kernel 13 | RUST_TEST_THREADS=1 cargo test --test s10* -- s10_memcached_benchmark 14 | ``` 15 | 16 | This test will spawn memcached on one, two and four threads and measure 17 | throughput and latency with 18 | [memaslap](./Memcached.html#memaslap-load-generator). 19 | 20 | ## Launch memcached manually 21 | 22 | Start the server binary on the VM instance: 23 | 24 | ```bash 25 | cd kernel 26 | python3 run.py \ 27 | --kfeatures test-userspace-smp \ 28 | --cmd 'log=info init=memcached.bin' \ 29 | --nic virtio \ 30 | --mods rkapps \ 31 | --qemu-settings='-m 1024M' \ 32 | --ufeatures 'rkapps:memcached' \ 33 | --release \ 34 | --qemu-cores 4 \ 35 | --verbose 36 | ``` 37 | 38 | As usual, make sure `dhcpd` is running on the host: 39 | 40 | ```bash 41 | cd kernel 42 | sudo service apparmor teardown 43 | sudo dhcpd -f -d tap0 --no-pid -cf ./tests/dhcpd.conf 44 | ``` 45 | 46 | Start the load-generater on the host: 47 | 48 | ```bash 49 | memaslap -s 172.31.0.10 -t 10s -S 10s 50 | ``` 51 | 52 | ## memaslap: Load generator 53 | 54 | memaslap measures throughput and latency of a memcached instance. You can invoke 55 | it like this: 56 | 57 | ```bash 58 | memaslap -s 172.31.0.10:11211 -B -S 1s 59 | ``` 60 | 61 | Explanation of arguments: 62 | 63 | - `-B`: Use the binary protocol (faster than the ASCII variant) 64 | - `-S 1s`: Dump statistics every X seconds 65 | 66 | The other defaults arguments the tool assumes are: 67 | 68 | - 8 client threads with concurrency of 128 sockets 69 | - 1000000 requests 70 | - SET proportion: 10% 71 | - GET proportion: 90% 72 | 73 | > Unfortunately, the memaslap binary does not come with standard ubuntu 74 | > packages. Follow the [steps in the CI 75 | > guide](../configuration/CI.html#install-memaslap) to install it from sources. 76 | -------------------------------------------------------------------------------- /doc/src/benchmarking/Microbenchmarks.md: -------------------------------------------------------------------------------- 1 | # Microbenchmarks 2 | 3 | ## File-system 4 | 5 | The code contains an implementation of the 6 | [fxmark](https://www.usenix.org/system/files/conference/atc16/atc16_paper-min.pdf) 7 | benchmark suite. The benchmark code is located at `usr/init/src/fxmark`. 8 | 9 | To run the fxmark benchmarks invoke the following command: 10 | 11 | ```bash 12 | RUST_TEST_THREADS=1 cargo test --test s10* -- s10_fxmark_bench --nocapture 13 | ``` 14 | 15 | fxmark supports several different file benchmarks: 16 | 17 | * *drbh*: Read a shared block in a shared file 18 | * *drbl*: Read a block in a private file. 19 | * *dwol*: Overwrite a block in a private file. 20 | * *dwom*: Overwrite a private block in a shared file. 21 | * *mwrl*: Rename a private file in a private directory. 22 | * *mwrm*: Move a private file to a shared directory. 23 | * *mix*: Access/overwrite a random block (with fixed percentages) in a shared 24 | file. 25 | 26 | > By default the integration test might not run all benchmarks, you can modify 27 | > the CI code to change what benchmarks are run or study it to determine how to 28 | > supply the correct arguments to `run.py`. 29 | 30 | ## Address-space 31 | 32 | The following integration tests benchmark the address-space in nrk: 33 | 34 | * `s10_vmops_benchmark`: This benchmark repeatedly inserts the same frame over 35 | and over in the process' address space, while varying the number of cores that 36 | do insertions. Every core works in its own partition of the address space. The 37 | system measures the throughput (operations per second). 38 | 39 | * `s10_vmops_latency_benchmark`: Same as `s10_vmops_benchmark`, but measure 40 | latency instead of throughput. 41 | 42 | * `s10_vmops_unmaplat_latency_benchmark`: The benchmark maps a frame in the 43 | address space, then spawns a series of threads on other cores that access the 44 | frame, afterwards it unmaps the frame and measures the latency of the unmap 45 | operation (the latency is dominated by completing the TLB shootdown protocol 46 | on all cores). 47 | 48 | * `s10_shootdown_simple`: The benchmark measures the overhead in the kernel for 49 | programming the APIC and sending IPIs to initiate and complete the shootdown 50 | protocol. 51 | 52 | The benchmark code is located at `usr/init/src/vmops/`. To invoke the 53 | benchmarks, run: 54 | 55 | ```bash 56 | RUST_TEST_THREADS=1 cargo test --test s10* -- s10_vmops_benchmark --nocapture 57 | RUST_TEST_THREADS=1 cargo test --test s10* -- s10_vmops_latency_benchmark --nocapture 58 | RUST_TEST_THREADS=1 cargo test --test s10* -- s10_vmops_unmaplat_latency_benchmark --nocapture 59 | RUST_TEST_THREADS=1 cargo test --test s10* -- s10_shootdown_simple --nocapture 60 | ``` 61 | 62 | ## Network 63 | 64 | TBD. 65 | -------------------------------------------------------------------------------- /doc/src/development/Configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | Some tips and pointers for setting up and configuring the development environment. 4 | 5 | ## VSCode 6 | 7 | VSCode generally works well for developing nrk. The `rust-analyzer` plugin is 8 | preferred over `rls` which often has build issues due to the project not having 9 | a std runtime (`no-std`). 10 | 11 | ## Git 12 | 13 | For first time git users or new accounts, you'll have to configure your username 14 | and email: 15 | 16 | ```bash 17 | git config --global user.name "Gerd Zellweger" 18 | git config --global user.email "mail@gerdzellweger.com" 19 | ``` 20 | 21 | To have better usability when working with submodules, you can configure git to 22 | update submodules automatically when doing a `git pull` etc. 23 | 24 | ```bash 25 | git config --global submodule.recurse true 26 | ``` 27 | 28 | Fetch multiple submodules in parallel: 29 | 30 | ```bash 31 | git config --global submodule.fetchJobs 20 32 | ``` 33 | 34 | We don't allow merge requests on master, to always keep a linear history. The 35 | following alias can be helpful: 36 | 37 | ```gitconfig 38 | [alias] 39 | purr = pull --rebase 40 | ``` 41 | 42 | ### Adding a new submodule to the repository 43 | 44 | 1. `cd lib` 45 | 1. `git submodule add ` 46 | 47 | ### Removing a submodule in the repository 48 | 49 | 1. Delete the relevant section from the .gitmodules file. 50 | 1. Stage the .gitmodules changes: `git add .gitmodules`. 51 | 1. Delete the relevant section from .git/config. 52 | 1. Run `git rm --cached path_to_submodule` (no trailing slash). 53 | 1. Run `rm -rf .git/modules/path_to_submodule` (no trailing slash). 54 | 1. Commit changes -------------------------------------------------------------------------------- /doc/src/development/Styleguide.md: -------------------------------------------------------------------------------- 1 | # Styleguide 2 | 3 | ## Code format 4 | 5 | We rely on [rustfmt](https://github.com/rust-lang/rustfmt) to automatically format our code. 6 | 7 | ## Code organization 8 | 9 | We organize/separate imports into three blocks (all separated by one newline): 10 | 11 | - 1st block for core language things: `core`, `alloc`, `std` etc. 12 | - 2nd block for libraries: `vibrio`, `x86`, `lazy_static` etc. 13 | - 3rd block for internal imports: `crate::*`, `super::*` etc. 14 | - 4th block for re-exports: `pub(crate) use::*` etc. 15 | - 5th block for modules: `mod foo;` etc. 16 | 17 | Afterwards a `.rs` file should (roughly) have the following structure: 18 | 19 | - 1st `type` declarations 20 | - 2nd `const` declarations 21 | - 3rd `static` declarations 22 | - 4th `struct`, `fn`, `impl` etc. declarations 23 | 24 | ## Visibility 25 | 26 | Avoid the use of `pub` in the kernel. Use `pub(crate)`, `pub(super)` etc. This 27 | helps with dead code elimination. 28 | 29 | ## Assembly 30 | 31 | We use AT&T syntax for assembly code (`options(att_syntax)` in Rust `asm!` 32 | blocks) 33 | 34 | ## Cargo features 35 | 36 | Libraries and binaries only have non-additive / non-conflicting feature flags. 37 | This helps to spot compilation problems quickly (e.g. with `cargo build 38 | --all-features`) 39 | 40 | ## Errors 41 | 42 | The `KError` type is used to represent errors in the kernel. Whenever possible, 43 | each variant should only be used once/in a single location (to be easy to grep 44 | for) and should have a descriptive name. 45 | 46 | ## Formatting Commit Messages 47 | 48 | We follow the conventions on [How to Write a Git Commit 49 | Message](http://chris.beams.io/posts/git-commit/). 50 | 51 | Be sure to include any related GitHub issue references in the commit message. 52 | See [GFM 53 | syntax](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown) 54 | for referencing issues and commits. 55 | 56 | ## Github pull requests & history 57 | 58 | Since github doesn't do fast-forward merges through the UI, after PR passes 59 | test, merge it on the command line to keep the same commit hashes of the branch 60 | in master: 61 | 62 | ```bash 63 | git checkout master 64 | git merge --ff-only feature-branch-name 65 | ``` 66 | -------------------------------------------------------------------------------- /doc/src/development/Tracing.md: -------------------------------------------------------------------------------- 1 | # Tracing 2 | 3 | Use Intel PT (processor-trace). TBD. -------------------------------------------------------------------------------- /doc/src/diagrams/AddressSpaceLayout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/AddressSpaceLayout.png -------------------------------------------------------------------------------- /doc/src/diagrams/CNROverview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/CNROverview.png -------------------------------------------------------------------------------- /doc/src/diagrams/DetMemAllocator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/DetMemAllocator.png -------------------------------------------------------------------------------- /doc/src/diagrams/FrameCacheLarge-FrameCacheSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/FrameCacheLarge-FrameCacheSmall.png -------------------------------------------------------------------------------- /doc/src/diagrams/LogBasedArchitecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/LogBasedArchitecture.png -------------------------------------------------------------------------------- /doc/src/diagrams/NrFlatCombiner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/NrFlatCombiner.png -------------------------------------------------------------------------------- /doc/src/diagrams/NrLog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/NrLog.png -------------------------------------------------------------------------------- /doc/src/diagrams/NrRWLock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/NrRWLock.png -------------------------------------------------------------------------------- /doc/src/diagrams/Process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/Process.png -------------------------------------------------------------------------------- /doc/src/diagrams/Slabmalloc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/Slabmalloc.png -------------------------------------------------------------------------------- /doc/src/diagrams/advance-head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/advance-head.png -------------------------------------------------------------------------------- /doc/src/diagrams/log-memory-layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/log-memory-layout.png -------------------------------------------------------------------------------- /doc/src/diagrams/tail-head-ctail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/diagrams/tail-head-ctail.png -------------------------------------------------------------------------------- /doc/src/environment/Environment.md: -------------------------------------------------------------------------------- 1 | # Environment 2 | 3 | This chapter contains various notes on configuration and setup of the host 4 | system (Linux), and the hypervisor (QEMU) to use either pass-through or emulate 5 | various technologies for the nrkernel and develop for it. 6 | 7 | ## Install QEMU from sources 8 | 9 | Make sure the QEMU version for the account is is >= 6 . The following steps can 10 | be used to build it from scratch, if it the Ubuntu release has a lesser version 11 | in the package repository. 12 | 13 | First, make sure to uncomment all #deb-src lines in /etc/apt/sources.list if not 14 | already uncommented. Then, run the following commands: 15 | 16 | For any build: 17 | ```bash 18 | sudo apt update 19 | sudo apt install build-essential libpmem-dev libdaxctl-dev ninja-build flex bison 20 | apt source qemu 21 | sudo apt build-dep qemu 22 | ``` 23 | 24 | For non-rackscale: 25 | ```bash 26 | wget https://download.qemu.org/qemu-6.0.0.tar.xz 27 | tar xvJf qemu-6.0.0.tar.xz 28 | cd qemu-6.0.0 29 | ``` 30 | 31 | For non-rackscale OR rackscale: 32 | ```bash 33 | git clone https://github.com/hunhoffe/qemu.git qemu-6.0.0 34 | cd qemu-6.0.0 35 | git checkout --track origin/dev/ivshmem-numa 36 | ``` 37 | 38 | For any build: 39 | ```bash 40 | ./configure --enable-rdma --enable-libpmem 41 | make -j 28 42 | sudo make -j28 install 43 | sudo make rdmacm-mux 44 | 45 | # Check version (should be >=6.0.0) 46 | qemu-system-x86_64 --version 47 | ``` 48 | 49 | You can also add `--enable-debug` to the configure script which will add debug 50 | information (useful for source information when stepping through qemu code in 51 | gdb). 52 | 53 | Note that sometimes ```make install``` doesn't actually replace the 54 | ```ivshmem-server```. Use ```which ivshmem-server``` to find the current 55 | location and then overwrite it with 56 | ```qemu/build/contrib/ivshmem-server/ivshmem-server```. 57 | -------------------------------------------------------------------------------- /doc/src/environment/rdma.md: -------------------------------------------------------------------------------- 1 | # Use RDMA support in QEMU 2 | 3 | > **tldr:** The `-pvrdma` option in `run.py` will enable RDMA support in QEMU. 4 | > However, you'll manually have to run `rdmacm-mux` and unload the Mellanox 5 | > modules at the moment. 6 | 7 | QEMU has support for `pvrdma` (a para-virtual RDMA driver) which integrates with 8 | physical cards (like Mellanox). In order to use it (aside from the 9 | `--enable-rdma` flag and `sudo make rdmacm-mux` during building), the following 10 | steps are necessary: 11 | 12 | Install Mellanox drivers (or any other native drivers for your RDMA card): 13 | 14 | ```bash 15 | wget https://content.mellanox.com/ofed/MLNX_OFED-5.4-1.0.3.0/MLNX_OFED_LINUX-5.4-1.0.3.0-ubuntu20.04-x86_64.tgz 16 | tar zxvf MLNX_OFED_LINUX-5.4-1.0.3.0-ubuntu20.04-x86_64.tgz 17 | cd MLNX_OFED_LINUX-5.4-1.0.3.0-ubuntu20.04-x86_64 18 | ./mlnxofedinstall --all 19 | ``` 20 | 21 | Before running the rdmacm-mux make sure that both ib_cm and rdma_cm kernel 22 | modules aren't loaded, otherwise the rdmacm-mux service will fail to start: 23 | 24 | ```bash 25 | sudo rmmod ib_ipoib 26 | sudo rmmod rdma_cm 27 | sudo rmmod ib_cm 28 | ``` 29 | 30 | Start the QEMU `racadm-mux` utility (before launching a qemu VM that uses 31 | pvrdma): 32 | 33 | ```bash 34 | ./rdmacm-mux -d mlx5_0 -p 0 35 | ``` 36 | -------------------------------------------------------------------------------- /doc/src/userspace/KPI.md: -------------------------------------------------------------------------------- 1 | # KPI: Kernel Public Interface 2 | 3 | The Kernel Public Interface (KPI) is the lowest level user-space library that an 4 | application links with. As the name suggests it is the common interface 5 | definition between the kernel and user-space programs. It is special because it 6 | is the only library that is shared between user and kernel code. 7 | 8 | The KPI contains the syscall interface and various struct definitions that are 9 | exchanged between the kernel and user-space. If in the future, we care about ABI 10 | compatibility, we would not try to keep the syscall ABI compatible but would 11 | rather enforce compatibility at the KPI boundary. 12 | 13 | Typically, the KPI functionality will rarely be accessed directly by an 14 | application. Instead, many parts of it are re-exported or wrapped by the 15 | [vibrio](./Vibrio.html) library OS. The `kpi` code is found in `lib/kpi`. 16 | -------------------------------------------------------------------------------- /doc/src/userspace/Lineup.md: -------------------------------------------------------------------------------- 1 | # Lineup 2 | 3 | Lineup is a user-space, cooperative thread scheduler that runs green-threads 4 | (user-level threads). It supports many synchronization primitives (mutex, 5 | rwlock, conditional variables, barriers etc.), thread-local storage, and has 6 | some basic support for multi-threading. It uses 7 | [fringe](https://crates.io/crates/fringe) for compiler-assisted 8 | context-switching. The scheduler code is found in `lib/lineup`. 9 | 10 | ## Upcalls 11 | 12 | The kernel can notify the scheduler about events through an up-call mechanism, 13 | for example to notify about more available cores (or removal of cores), to 14 | forward device interrupts, or page-faults from kernel to user-space. 15 | 16 | The mechanism for this is inspired by scheduler activations: The kernel and 17 | user-space program agree on a common save area to store a CPU context (on a 18 | per-core basis). If an event arrives at the kernel, it will save the current CPU 19 | context (registers etc.) in the agreed upon save-area and resume the process 20 | with a new (mostly empty) context that invokes the pre-registered upcall handler 21 | instead. The upcall handler gets all information about the event that triggered 22 | the interruption through function arguments so it can then take appropriate 23 | measures to react. After the event is handled, the upcall handler can read the 24 | previous context (from before the interruption) from the common save area and 25 | decide to resume where computation left off before the upcall (or decide not to 26 | continue with this context). 27 | -------------------------------------------------------------------------------- /doc/src/userspace/Memory.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmware-labs/node-replicated-kernel/38557a67be10c249853300560cc7e1d09f90c8aa/doc/src/userspace/Memory.md -------------------------------------------------------------------------------- /doc/src/userspace/UserSpace.md: -------------------------------------------------------------------------------- 1 | # User Space 2 | 3 | The main user-space components are explained in more details in this chapter. -------------------------------------------------------------------------------- /doc/src/userspace/Vibrio.md: -------------------------------------------------------------------------------- 1 | # Vibrio 2 | 3 | Virbio is the user-space library that provides most of the functionality 4 | necessary to run applications in user-space. It is found in `lib/vibrio`. 5 | 6 | ## Memory 7 | 8 | The user-space memory manager provides a `malloc` and `free` like interface for 9 | C code and a `GlobalAlloc` implementation for rust programs. We rely on the 10 | [same allocator](../architecture/Memory.html#dynamic-memory) that the kernel 11 | uses for small--medium sized blocks (between 0 and 2 MiB). Everything else is 12 | mapped directly by allocating memory with the map syscall. 13 | 14 | ## RumpRT 15 | 16 | A rumpkernels is a componentized NetBSD kernel that can run in many different 17 | environments. It contains file systems, a POSIX system call interface, many PCI 18 | device drivers, a SCSI protocol stack, virtio, a TCP/IP stack, libc and 19 | libpthread and more. 20 | 21 | Vibrio has a `rumprt` module which provides the necessary low-level interface to 22 | run a rumpkernel inside a user-space process (e.g., the 23 | [rumpuser](https://man.netbsd.org/rumpuser.3) API and some more). This has the 24 | advantage that it's possible to run many POSIX compatible programs out of the 25 | box without building a fully-fledged POSIX compatibility layer into NrOS. 26 | 27 | - Bare-metal and Xen implementations for [rumprun](https://github.com/rumpkernel/rumprun) 28 | - [Some supported applications](https://github.com/rumpkernel/rumprun-packages) 29 | - [PhD thesis about rumpkernels](https://research.aalto.fi/en/publications/flexible-operating-system-internals-the-design-and-implementation) 30 | 31 | ## Vibrio dependency graph 32 | 33 | Vibrio uses the following crates / dependencies: 34 | 35 | ```log 36 | vibrio 37 | ├── arrayvec 38 | ├── bitflags 39 | ├── crossbeam-utils 40 | ├── cstr_core 41 | ├── hashbrown 42 | ├── kpi 43 | ├── lazy_static 44 | ├── lineup 45 | ├── log 46 | ├── rawtime 47 | ├── rumpkernel 48 | ├── serde_cbor 49 | ├── slabmalloc 50 | ├── spin 51 | └── x86 52 | ``` 53 | -------------------------------------------------------------------------------- /doc/src/userspace/rkapps.md: -------------------------------------------------------------------------------- 1 | # rkapps 2 | 3 | The rkapps directory (in `usr/rkapps`) is an empty project aside from the 4 | `build.rs` file. The build file contains the steps to clone and build a few 5 | different well-known programs (memcached, LevelDB, Redis etc.) that we use to 6 | test user-space and rumprt. 7 | 8 | The checked-out program sources and binaries are placed in the following 9 | location as part of your build directory: 10 | 11 | ```target/x86_64-nrk-none//build/rkapps-$HASH/out/``` 12 | 13 | The build for these programs can be a bit hard to understand. The following 14 | steps happen: 15 | 16 | 1. Clone the packages repo which has build instructions for different POSIX 17 | programs running on rumpkernels. 18 | 2. For each application that we want to build (enabled/disabled by feature 19 | flags): Run `make` in the respective directory. This will compile the 20 | application with the appropriate rumpkernel toolchain. The toolchain be found 21 | in a similar path inside the build directory: 22 | `target/x86_64-nrk-none//build/rumpkernel-$HASH` 23 | 3. Linking binaries with vibrio which provides the low-level runtime for 24 | rumpkernels. 25 | 26 | 27 | > For more information on how to run rkapps applications, refer to the 28 | > [Benchmarking](..//benchmarking/Benchmarking.html) section. -------------------------------------------------------------------------------- /kernel/.cargo/config: -------------------------------------------------------------------------------- 1 | [target.x86_64-nrk] 2 | rustflags = [ 3 | "-C", "target-feature=+sse2", 4 | # "--cfg", "no_global_oom_handling" 5 | ] 6 | -------------------------------------------------------------------------------- /kernel/.gdbinit: -------------------------------------------------------------------------------- 1 | target remote localhost:1234 -------------------------------------------------------------------------------- /kernel/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | extern crate cc; 5 | 6 | use std::env; 7 | use std::process::Command; 8 | 9 | fn main() { 10 | // macos currently can't deal with assembly 11 | if std::env::consts::OS == "linux" && env::var("TARGET").unwrap() == "x86_64-nrk" { 12 | env::set_var("CC", "gcc"); 13 | println!("cargo:rerun-if-changed=src/arch/x86_64/start_ap.S"); 14 | println!("cargo:rerun-if-changed=src/arch/x86_64/exec.S"); 15 | println!("cargo:rerun-if-changed=src/arch/x86_64/acpi_printf.c"); 16 | println!("cargo:rerun-if-changed=src/arch/x86_64/acpi_printf.h"); 17 | 18 | cc::Build::new() 19 | .flag("-m64") 20 | .flag("-fno-builtin") 21 | .flag("-nostdlib") 22 | .flag("-U__linux__") 23 | .flag("-shared") 24 | .flag("-nostartfiles") 25 | .flag("-fPIC") 26 | .flag("-Wno-unused-parameter") 27 | .file("src/arch/x86_64/start_ap.S") 28 | .file("src/arch/x86_64/exec.S") 29 | .file("src/arch/x86_64/acpi_printf.c") 30 | .pic(true) 31 | .warnings(true) 32 | //.cargo_metadata(false) 33 | .compile("nrk_asm"); 34 | } 35 | 36 | let output = Command::new("git") 37 | .args(["rev-parse", "HEAD"]) 38 | .output() 39 | .expect("Could not determine git hash"); 40 | let git_hash = String::from_utf8(output.stdout).expect("Could not parse the git hash"); 41 | println!("cargo:rustc-env=GIT_HASH={}", git_hash); 42 | } 43 | -------------------------------------------------------------------------------- /kernel/cmdline.in: -------------------------------------------------------------------------------- 1 | ./kernel 2 | -------------------------------------------------------------------------------- /kernel/commitable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | # 5 | # Makes sure that tests in CI will pass (hopefully). 6 | # 7 | 8 | # check formatting 9 | cd .. 10 | cargo fmt -- --check 11 | cd kernel 12 | 13 | # build kernel 14 | RUST_TARGET_PATH=`pwd`/src/arch/x86_64 cargo build -Z build-std=core,alloc -Z build-std-features=compiler-builtins-mem -v --target=x86_64-nrk 15 | 16 | # Try to compile with all/most of the code enabled 17 | python3 run.py --kfeatures ethernet shmem rackscale integration-test gdb --kgdb --norun 18 | # run kernel 19 | python3 run.py 20 | 21 | # run unix architecture 22 | cargo run 23 | 24 | # compile init binary 25 | cd ../usr/init 26 | RUST_TARGET_PATH=`pwd`/../ cargo build -Z build-std=core,alloc -Z build-std-features=compiler-builtins-mem --target x86_64-nrk-none --color always --release --all-features 27 | cd ../../kernel 28 | 29 | # run integration tests 30 | RUST_TEST_THREADS=1 cargo test --features smoke -- --nocapture 31 | 32 | # Testing stuff under lib/ 33 | cd ../lib/apic && cargo test --all-features 34 | cd ../bootloader_shared && cargo test --all-features 35 | cd ../kpi && cargo test --all-features 36 | cd ../vibrio && cargo test --all-features 37 | cd ../vmxnet3 && cargo test --all-features 38 | cd ../rpc && cargo test --all-features 39 | 40 | # Documentation 41 | cd ../../doc && mdbook build -------------------------------------------------------------------------------- /kernel/src/arch/unix/coreboot.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use alloc::sync::Arc; 5 | use core::sync::atomic::AtomicBool; 6 | 7 | use crate::stack::Stack; 8 | 9 | /// Starts up the core identified by `core_id`, after initialization it begins 10 | /// to executing in `init_function` and uses `stack` as a stack. 11 | /// 12 | /// # Safety 13 | /// This is likely to be pretty safe on `unix` but not so much on bare-metal 14 | /// hardware. 15 | pub unsafe fn initialize( 16 | _core_id: x86::apic::ApicId, 17 | _init_function: fn(Arc, &AtomicBool), 18 | _args: Arc, 19 | _initialized: &AtomicBool, 20 | _stack: &dyn Stack, 21 | ) { 22 | unimplemented!("initialize is not implemented"); 23 | } 24 | -------------------------------------------------------------------------------- /kernel/src/arch/unix/debug.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use super::ExitReason; 5 | use klogger::sprintln; 6 | 7 | /// Shutdown the process. 8 | pub(crate) fn shutdown(val: ExitReason) -> ! { 9 | sprintln!("Shutdown {:?}", val); 10 | 11 | unsafe { 12 | libc::exit(val as i32); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /kernel/src/arch/unix/irq.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | pub(crate) fn enable() {} 5 | 6 | pub(crate) fn disable() {} 7 | -------------------------------------------------------------------------------- /kernel/src/arch/unix/kcb.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! KCB is the local kernel control that stores all core local state. 5 | 6 | use alloc::sync::Arc; 7 | use core::any::Any; 8 | 9 | use arrayvec::ArrayVec; 10 | use node_replication::{Replica, ReplicaToken}; 11 | 12 | use crate::error::KError; 13 | use crate::memory::mcache::FrameCacheEarly; 14 | use crate::memory::per_core::PerCoreMemory; 15 | use crate::nr::KernelNode; 16 | use crate::nrproc::NrProcess; 17 | use crate::process::MAX_PROCESSES; 18 | 19 | use super::process::{UnixProcess, UnixThread}; 20 | use super::MAX_NUMA_NODES; 21 | 22 | #[thread_local] 23 | pub(crate) static mut PER_CORE_MEMORY: PerCoreMemory = 24 | PerCoreMemory::new(FrameCacheEarly::new(0), 0); 25 | 26 | #[thread_local] 27 | static mut KCB: ArchKcb = ArchKcb; 28 | 29 | pub(crate) fn try_get_kcb<'a>() -> Option<&'a mut ArchKcb> { 30 | unsafe { Some(&mut KCB) } 31 | } 32 | 33 | pub(crate) fn get_kcb<'a>() -> &'a mut ArchKcb { 34 | unsafe { &mut KCB } 35 | } 36 | 37 | pub(crate) fn try_per_core_mem() -> Option<&'static PerCoreMemory> { 38 | unsafe { Some(&PER_CORE_MEMORY) } 39 | } 40 | 41 | /// Stands for per-core memory 42 | pub(crate) fn per_core_mem() -> &'static PerCoreMemory { 43 | unsafe { &PER_CORE_MEMORY } 44 | } 45 | 46 | /// Initialize the KCB in the system. 47 | /// 48 | /// Should be called during set-up. Afterwards we can use `get_kcb` safely. 49 | pub(crate) fn init_kcb(mut _kcb: &'static mut PerCoreMemory) { 50 | //unreachable!("init_kcb."); 51 | } 52 | 53 | #[repr(C)] 54 | pub(crate) struct ArchKcb; 55 | -------------------------------------------------------------------------------- /kernel/src/arch/unix/memory.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use core::mem::transmute; 5 | 6 | use log::error; 7 | pub use x86::bits64::paging::{PAddr, VAddr, BASE_PAGE_SIZE, CACHE_LINE_SIZE, LARGE_PAGE_SIZE}; 8 | 9 | use crate::memory::Frame; 10 | 11 | /// Maximum amount of addressable physical memory in kernel (32 TiB). 12 | pub(crate) const KERNEL_BASE: u64 = 0x0; 13 | 14 | /// Translate a kernel 'virtual' address to the physical address of the memory. 15 | pub(crate) fn kernel_vaddr_to_paddr(v: VAddr) -> PAddr { 16 | let vaddr_val: usize = v.into(); 17 | PAddr::from(vaddr_val as u64 - KERNEL_BASE) 18 | } 19 | 20 | /// Translate a physical memory address into a kernel addressable location. 21 | pub(crate) fn paddr_to_kernel_vaddr(p: PAddr) -> VAddr { 22 | let paddr_val: u64 = p.into(); 23 | VAddr::from((paddr_val + KERNEL_BASE) as usize) 24 | } 25 | 26 | /// Page allocator based on mmap/munmap system calls for backing slab memory. 27 | #[derive(Default)] 28 | pub(crate) struct MemoryMapper { 29 | /// Currently allocated bytes. 30 | currently_allocated: usize, 31 | } 32 | 33 | impl MemoryMapper { 34 | pub(crate) fn currently_allocated(&self) -> usize { 35 | self.currently_allocated 36 | } 37 | 38 | /// Allocates a new Frame from the system. 39 | /// 40 | /// Uses `mmap` to map. 41 | pub(crate) fn allocate_frame(&mut self, size: usize) -> Option { 42 | if size % BASE_PAGE_SIZE != 0 { 43 | return None; 44 | } 45 | let mut addr: *mut libc::c_void = core::ptr::null_mut(); 46 | 47 | let alignment = match size { 48 | BASE_PAGE_SIZE => BASE_PAGE_SIZE, 49 | _ => LARGE_PAGE_SIZE, 50 | }; 51 | 52 | let r = 53 | unsafe { libc::posix_memalign(&mut addr as *mut *mut libc::c_void, alignment, size) }; 54 | 55 | if r == 0 { 56 | let addr_ptr = addr as *const _ as *const u64; 57 | assert_eq!(addr_ptr as u64 % alignment as u64, 0); 58 | let frame = Frame::new(PAddr::from(addr_ptr as u64), size, 0); 59 | 60 | self.currently_allocated += size; 61 | Some(frame) 62 | } else { 63 | error!("Got posix memalign return {:?}", r); 64 | None 65 | } 66 | } 67 | 68 | /// Release a Frame back to the system. 69 | /// 70 | /// Uses `munmap` to release the page back to the OS. 71 | #[allow(unused)] 72 | fn release_frame(&mut self, p: Frame) { 73 | let addr: *mut libc::c_void = unsafe { transmute(p.base) }; 74 | let len: libc::size_t = p.size; 75 | unsafe { libc::free(addr) }; 76 | 77 | self.currently_allocated -= p.size; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /kernel/src/arch/unix/network.rs: -------------------------------------------------------------------------------- 1 | use smoltcp::iface::Interface; 2 | use vmxnet3::smoltcp::DevQueuePhy; 3 | 4 | pub(crate) fn init_network<'a>() -> Interface<'a, DevQueuePhy> { 5 | unimplemented!("init_network not implemented for unix"); 6 | } 7 | -------------------------------------------------------------------------------- /kernel/src/arch/unix/rackscale.rs: -------------------------------------------------------------------------------- 1 | use rpc::{ 2 | api::{RPCHandler, RegistrationHandler}, 3 | rpc::{RPCError, RPCHeader}, 4 | }; 5 | 6 | pub mod fio { 7 | pub use kpi::FileOperation as FileIO; 8 | } 9 | 10 | pub use fio::FileIO; 11 | 12 | fn default(_hdr: &mut RPCHeader, _payload: &mut [u8], _state: ()) -> Result<(), RPCError> { 13 | Err(RPCError::InternalError) 14 | } 15 | 16 | fn register(_hdr: &mut RPCHeader, _payload: &mut [u8], _state: ()) -> Result<(), RPCError> { 17 | Err(RPCError::InternalError) 18 | } 19 | 20 | pub(crate) const CLOSE_HANDLER: RPCHandler<()> = default; 21 | pub(crate) const DELETE_HANDLER: RPCHandler<()> = default; 22 | pub(crate) const GETINFO_HANDLER: RPCHandler<()> = default; 23 | pub(crate) const MKDIR_HANDLER: RPCHandler<()> = default; 24 | pub(crate) const OPEN_HANDLER: RPCHandler<()> = default; 25 | pub(crate) const RENAME_HANDLER: RPCHandler<()> = default; 26 | pub(crate) const READ_HANDLER: RPCHandler<()> = default; 27 | pub(crate) const WRITE_HANDLER: RPCHandler<()> = default; 28 | 29 | pub(crate) const CLIENT_REGISTRAR: RegistrationHandler<()> = register; 30 | -------------------------------------------------------------------------------- /kernel/src/arch/unix/signals.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Platform specific functions to deal with CNR 5 | 6 | pub(crate) fn advance_replica(mtid: kpi::system::MachineThreadId, log_id: usize) { 7 | log::warn!("advance_replica {} {} not implemented", mtid, log_id); 8 | // All metadata operations are done using log 1. So, make sure that the 9 | // replica has applied all those operation before any other log sync. 10 | match crate::fs::cnrfs::MlnrKernelNode::synchronize_log(1) { 11 | Ok(_) => { /* Simply return */ } 12 | Err(e) => unreachable!("Error {:?} while advancing the log {}", e, log_id), 13 | } 14 | 15 | if log_id != 1 { 16 | match crate::fs::cnrfs::MlnrKernelNode::synchronize_log(log_id) { 17 | Ok(_) => { /* Simply return */ } 18 | Err(e) => unreachable!("Error {:?} while advancing the log {}", e, log_id), 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /kernel/src/arch/unix/timer.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Timer API 5 | 6 | /// Default when to raise the next timer irq (in rdtsc ticks) 7 | pub(crate) const DEFAULT_TIMER_DEADLINE: u64 = 2_000_000_000; 8 | 9 | /// Register a periodic timer to advance replica. 10 | pub(crate) fn set(_deadline: u64) {} 11 | -------------------------------------------------------------------------------- /kernel/src/arch/unix/tlb.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use crate::memory::vspace::TlbFlushHandle; 5 | 6 | pub(crate) fn shootdown(handle: TlbFlushHandle) {} 7 | -------------------------------------------------------------------------------- /kernel/src/arch/unix/vspace.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! A dummy vspace implementation for the unix platform. 5 | 6 | use alloc::boxed::Box; 7 | 8 | use core::fmt; 9 | use core::pin::Pin; 10 | use hashbrown::HashMap; 11 | use lazy_static::lazy_static; 12 | use spin::Mutex; 13 | use x86::bits64::paging::*; 14 | 15 | use crate::error::KError; 16 | use crate::memory::vspace::{AddressSpace, MapAction, MappingInfo, TlbFlushHandle}; 17 | use crate::memory::Frame; 18 | 19 | lazy_static! { 20 | pub(crate) static ref INITIAL_VSPACE: Mutex = Mutex::new(VSpace::new()); 21 | } 22 | 23 | pub(crate) struct VSpace { 24 | pub mappings: HashMap, MappingInfo>, 25 | pub pml4: Pin>, 26 | } 27 | 28 | impl Default for VSpace { 29 | fn default() -> Self { 30 | VSpace::new() 31 | } 32 | } 33 | 34 | impl fmt::Debug for VSpace { 35 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 36 | f.debug_struct("VSpace").finish() 37 | } 38 | } 39 | 40 | impl VSpace { 41 | pub(crate) fn new() -> VSpace { 42 | VSpace { 43 | mappings: HashMap::new(), 44 | pml4: Box::pin( 45 | [PML4Entry::new(PAddr::from(0x0u64), PML4Flags::empty()); PAGE_SIZE_ENTRIES], 46 | ), 47 | } 48 | } 49 | 50 | pub(crate) fn map_generic( 51 | &mut self, 52 | _vbase: VAddr, 53 | _pregion: (PAddr, usize), 54 | _rights: MapAction, 55 | _create_mappings: bool, 56 | ) -> Result<(), KError> { 57 | Ok(()) 58 | } 59 | 60 | pub(crate) fn map_identity_with_offset( 61 | &mut self, 62 | at_offset: PAddr, 63 | pbase: PAddr, 64 | size: usize, 65 | rights: MapAction, 66 | ) -> Result<(), KError> { 67 | Ok(()) 68 | } 69 | } 70 | 71 | impl AddressSpace for VSpace { 72 | fn map_frame(&mut self, base: VAddr, frame: Frame, action: MapAction) -> Result<(), KError> { 73 | let ma = MappingInfo::new(frame, action); 74 | self.mappings.insert(ma.vrange(base), ma); 75 | unimplemented!("map_frame"); 76 | } 77 | 78 | fn map_memory_requirements(_base: VAddr, _frames: &[Frame]) -> usize { 79 | unimplemented!("map_memory_requirements"); 80 | } 81 | 82 | fn adjust(&mut self, _vaddr: VAddr, _rights: MapAction) -> Result<(VAddr, usize), KError> { 83 | unimplemented!("adjust"); 84 | } 85 | 86 | fn resolve(&self, _vaddr: VAddr) -> Result<(PAddr, MapAction), KError> { 87 | unimplemented!("resolve"); 88 | } 89 | 90 | fn unmap(&mut self, _vaddr: VAddr) -> Result { 91 | unimplemented!("unmap"); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/exec.S: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | .text 5 | .balign 4096 6 | 7 | // This is the entry point for syscall instruction. 8 | // The architecture knows about it because we loaded 9 | // the address of this symbol into IA32_LSTAR. 10 | // (see syscalls.rs) 11 | // For SYSCALL, the processor saves RFLAGS into R11 and 12 | // the RIP of the next instruction into RCX 13 | .extern syscall_handle 14 | .global syscall_enter 15 | syscall_enter: 16 | // Puts address of KCB in %gs and temporarily store user %gs in MSR IA32_KERNEL_GSBASE 17 | swapgs 18 | 19 | // Get the pointer to the kcb.save_area 20 | movq %gs:0x8, %rax 21 | 22 | // Save process context: 23 | // We don't save %rax since we use it to reference the save_area location 24 | // it's ok since it is a caller-saved register (and used to return the syscall error) 25 | movq %rbx, 1*8(%rax) 26 | movq %rcx, 2*8(%rax) 27 | movq %rdx, 3*8(%rax) 28 | movq %rsi, 4*8(%rax) 29 | movq %rdi, 5*8(%rax) 30 | movq %rbp, 6*8(%rax) 31 | movq %rsp, 7*8(%rax) 32 | movq %r8, 8*8(%rax) 33 | movq %r9, 9*8(%rax) 34 | movq %r10, 10*8(%rax) 35 | movq %r11, 11*8(%rax) 36 | movq %r12, 12*8(%rax) 37 | movq %r13, 13*8(%rax) 38 | movq %r14, 14*8(%rax) 39 | movq %r15, 15*8(%rax) 40 | // Save user IP in SaveArea.rip 41 | movq %rcx, 16*8(%rax) 42 | 43 | // Save vector registers 44 | fxsave 28*8(%rax) 45 | 46 | // Saves fs register 47 | rdfsbase %r15 48 | movq %r15, 19*8(%rax) 49 | 50 | // Write the fs register of the current core 51 | // (the TLS area is the first member of the KCB and it lives at 0x10(%gs)) 52 | movq %gs:0x10, %r15 53 | wrfsbase %r15 54 | 55 | // Find the syscall stack of the core (the stack top is the first member 56 | // of the KCB and it lives at 0x0(%gs)), 57 | movq %gs:0x0, %rsp 58 | movq %rsp, %rbp 59 | 60 | // The syscall instruction saved the user-space RIP 61 | // in %rcx, but %rcx is also the 4th argument 62 | // in System V calling conventions, therefore 63 | // we substitute %rcx with %r10 when doing 64 | // system-calls and correct our "mistake" here: 65 | movq %r10, %rcx 66 | 67 | // Ready to handle the system call (in rust): 68 | callq syscall_handle 69 | 70 | // We should not return here form syscall_handle 71 | // In case we do, cause a page-fault to ease debugging 72 | movq $0xdeada, %rax 73 | movq (%rax), %rax 74 | exec.loop: 75 | hlt 76 | jmp exec.loop 77 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/gdb/section_offsets.rs: -------------------------------------------------------------------------------- 1 | use gdbstub::target::ext::section_offsets::{Offsets, SectionOffsets}; 2 | 3 | use super::KernelDebugger; 4 | use crate::error::KError; 5 | 6 | impl SectionOffsets for KernelDebugger { 7 | /// Tells GDB where in memory the bootloader has put our kernel binary. 8 | fn get_section_offsets(&mut self) -> Result, KError> { 9 | let kernel_reloc_offset = crate::KERNEL_ARGS 10 | .get() 11 | .map_or(0x0, |args| args.kernel_elf_offset.as_u64()); 12 | Ok(Offsets::Sections { 13 | text: kernel_reloc_offset, 14 | data: kernel_reloc_offset, 15 | bss: None, 16 | }) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/isr.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use core::arch::global_asm; 5 | 6 | #[cfg(target_os = "none")] 7 | global_asm!(include_str!("isr.S"), options(att_syntax)); 8 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/dcm/node_registration.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use kpi::system::MachineId; 5 | use rpc::rpc::RPCType; 6 | 7 | use super::{DCMOps, DCM_CLIENT}; 8 | 9 | #[derive(Debug, Default)] 10 | #[repr(C)] 11 | struct NodeRegistrationRequest { 12 | mid: u64, 13 | cores: u64, 14 | memslices: u64, 15 | } 16 | const REQ_SIZE: usize = core::mem::size_of::(); 17 | 18 | impl NodeRegistrationRequest { 19 | /// # Safety 20 | /// - `self` must be valid NodeRegistrationRequest 21 | unsafe fn as_bytes(&self) -> &[u8; REQ_SIZE] { 22 | ::core::slice::from_raw_parts( 23 | (self as *const NodeRegistrationRequest) as *const u8, 24 | REQ_SIZE, 25 | ) 26 | .try_into() 27 | .expect("slice with incorrect length") 28 | } 29 | } 30 | 31 | #[derive(Debug, Default)] 32 | #[repr(C)] 33 | struct NodeRegistrationResponse { 34 | is_success: bool, 35 | } 36 | const RES_SIZE: usize = core::mem::size_of::(); 37 | 38 | impl NodeRegistrationResponse { 39 | /// # Safety 40 | /// - `self` must be valid NodeRegistrationResponse 41 | unsafe fn as_mut_bytes(&mut self) -> &mut [u8; RES_SIZE] { 42 | ::core::slice::from_raw_parts_mut( 43 | (self as *const NodeRegistrationResponse) as *mut u8, 44 | RES_SIZE, 45 | ) 46 | .try_into() 47 | .expect("slice with incorrect length") 48 | } 49 | } 50 | 51 | pub(crate) fn dcm_register_node(mid: MachineId, cores: u64, memslices: u64) -> bool { 52 | // Create request and space for response 53 | let req = NodeRegistrationRequest { 54 | mid: mid as u64, 55 | cores, 56 | memslices, 57 | }; 58 | let mut res = NodeRegistrationResponse { is_success: false }; 59 | 60 | // Send call, get allocation response in return 61 | { 62 | DCM_CLIENT 63 | .lock() 64 | .call( 65 | DCMOps::RegisterNode as RPCType, 66 | unsafe { &[req.as_bytes()] }, 67 | unsafe { &mut [res.as_mut_bytes()] }, 68 | ) 69 | .expect("Failed to send register node RPC to DCM"); 70 | } 71 | 72 | log::debug!("Registered node is successful? {:?}", res.is_success); 73 | return res.is_success; 74 | } 75 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/dcm/resource_release.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use kpi::system::MachineId; 5 | use rpc::rpc::RPCType; 6 | 7 | use super::{DCMOps, DCM_CLIENT}; 8 | 9 | #[derive(Debug, Default)] 10 | #[repr(C)] 11 | struct ResourceReleaseRequest { 12 | mid: u64, 13 | application: u64, 14 | cores: u64, 15 | memslices: u64, 16 | } 17 | const REQ_SIZE: usize = core::mem::size_of::(); 18 | 19 | impl ResourceReleaseRequest { 20 | /// # Safety 21 | /// - `self` must be valid ResourceReleaseRequest 22 | unsafe fn as_bytes(&self) -> &[u8; REQ_SIZE] { 23 | ::core::slice::from_raw_parts( 24 | (self as *const ResourceReleaseRequest) as *const u8, 25 | REQ_SIZE, 26 | ) 27 | .try_into() 28 | .expect("slice with incorrect length") 29 | } 30 | } 31 | 32 | #[derive(Debug, Default)] 33 | #[repr(C)] 34 | struct ResourceReleaseResponse { 35 | is_success: u64, 36 | } 37 | const RES_SIZE: usize = core::mem::size_of::(); 38 | 39 | impl ResourceReleaseResponse { 40 | /// # Safety 41 | /// - `self` must be valid ResourceReleaseResponse 42 | unsafe fn as_mut_bytes(&mut self) -> &mut [u8; RES_SIZE] { 43 | ::core::slice::from_raw_parts_mut( 44 | (self as *const ResourceReleaseResponse) as *mut u8, 45 | RES_SIZE, 46 | ) 47 | .try_into() 48 | .expect("slice with incorrect length") 49 | } 50 | } 51 | 52 | pub(crate) fn dcm_resource_release(mid: MachineId, pid: usize, is_core: bool) -> u64 { 53 | let req = ResourceReleaseRequest { 54 | mid: mid as u64, 55 | application: pid as u64, 56 | cores: if is_core { 1 } else { 0 }, 57 | memslices: if is_core { 0 } else { 1 }, 58 | }; 59 | let mut res = ResourceReleaseResponse { is_success: 0 }; 60 | log::debug!("Sending DCM a resource release request"); 61 | 62 | // Send call, get allocation response in return 63 | { 64 | DCM_CLIENT 65 | .lock() 66 | .call( 67 | DCMOps::ResourceRelease as RPCType, 68 | unsafe { &[req.as_bytes()] }, 69 | unsafe { &mut [res.as_mut_bytes()] }, 70 | ) 71 | .expect("Failed to send resource release RPC to DCM"); 72 | } 73 | log::debug!( 74 | "Received is_success for DCM resource release: {:?}", 75 | res.is_success 76 | ); 77 | return res.is_success; 78 | } 79 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/fileops/close.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use abomonation::{decode, encode, unsafe_abomonate, Abomonation}; 5 | use core2::io::Result as IOResult; 6 | use core2::io::Write; 7 | 8 | use rpc::rpc::*; 9 | 10 | use crate::error::{KError, KResult}; 11 | use crate::fs::cnrfs; 12 | use crate::fs::fd::FileDescriptor; 13 | 14 | use super::super::kernelrpc::*; 15 | use super::super::CLIENT_STATE; 16 | use super::FileIO; 17 | 18 | #[derive(Debug)] 19 | pub(crate) struct CloseReq { 20 | pub pid: usize, 21 | pub fd: FileDescriptor, 22 | } 23 | unsafe_abomonate!(CloseReq: pid, fd); 24 | 25 | pub(crate) fn rpc_close(pid: usize, fd: FileDescriptor) -> KResult<(u64, u64)> { 26 | log::debug!("Close({:?})", fd); 27 | 28 | // Setup request data 29 | let req = CloseReq { pid, fd }; 30 | let mut req_data = [0u8; core::mem::size_of::()]; 31 | unsafe { encode(&req, &mut (&mut req_data).as_mut()) }.expect("Failed to encode close request"); 32 | 33 | // Setup result 34 | let mut res_data = [0u8; core::mem::size_of::>()]; 35 | 36 | // Call Close() RPC 37 | CLIENT_STATE.rpc_client.lock().call( 38 | KernelRpc::Close as RPCType, 39 | &[&req_data], 40 | &mut [&mut res_data], 41 | )?; 42 | 43 | // Decode and return result 44 | if let Some((res, remaining)) = unsafe { decode::>(&mut res_data) } { 45 | // Check for extra data 46 | if remaining.len() > 0 { 47 | Err(KError::from(RPCError::ExtraData)) 48 | } else { 49 | log::debug!("Close() {:?}", res); 50 | *res 51 | } 52 | 53 | // Report malformed data if failed to decode result 54 | } else { 55 | Err(KError::from(RPCError::MalformedResponse)) 56 | } 57 | } 58 | 59 | // RPC Handler function for close() RPCs in the controller 60 | pub(crate) fn handle_close(hdr: &mut RPCHeader, payload: &mut [u8]) -> Result<(), RPCError> { 61 | // Decode request 62 | let ret = if let Some((req, _)) = unsafe { decode::(payload) } { 63 | log::debug!("Close(pid={:?}), fd={:?}", req.pid, req.fd); 64 | cnrfs::MlnrKernelNode::unmap_fd(req.pid, req.fd) 65 | // Report error if failed to decode request 66 | } else { 67 | Err(KError::from(RPCError::MalformedRequest)) 68 | }; 69 | construct_ret(hdr, payload, ret); 70 | Ok(()) 71 | } 72 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/fileops/delete.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use alloc::string::String; 5 | 6 | use abomonation::{decode, encode, unsafe_abomonate, Abomonation}; 7 | use core2::io::Result as IOResult; 8 | use core2::io::Write; 9 | use rpc::rpc::*; 10 | 11 | use crate::error::{KError, KResult}; 12 | use crate::fallible_string::TryString; 13 | use crate::fs::cnrfs; 14 | 15 | use super::super::fileops::get_str_from_payload; 16 | use super::super::kernelrpc::*; 17 | use super::FileIO; 18 | use crate::arch::rackscale::CLIENT_STATE; 19 | 20 | #[derive(Debug)] 21 | pub(crate) struct DeleteReq { 22 | pub pid: usize, 23 | } 24 | unsafe_abomonate!(DeleteReq: pid); 25 | 26 | pub(crate) fn rpc_delete(pid: usize, pathname: String) -> KResult<(u64, u64)> { 27 | log::debug!("Delete({:?})", pathname); 28 | 29 | // Construct request data 30 | let req = DeleteReq { pid }; 31 | let mut req_data = [0u8; core::mem::size_of::()]; 32 | unsafe { encode(&req, &mut (&mut req_data).as_mut()) } 33 | .expect("Failed to encode delete request"); 34 | 35 | // Create buffer for result 36 | let mut res_data = [0u8; core::mem::size_of::>()]; 37 | 38 | // Call RPC 39 | CLIENT_STATE.rpc_client.lock().call( 40 | KernelRpc::Delete as RPCType, 41 | &[&req_data, &pathname.as_bytes()], 42 | &mut [&mut res_data], 43 | )?; 44 | 45 | // Decode result - return result if decoding successful 46 | if let Some((res, remaining)) = unsafe { decode::>(&mut res_data) } { 47 | if remaining.len() > 0 { 48 | return Err(KError::from(RPCError::ExtraData)); 49 | } 50 | log::debug!("Delete() {:?}", res); 51 | return *res; 52 | } else { 53 | return Err(KError::from(RPCError::MalformedResponse)); 54 | } 55 | } 56 | 57 | // RPC Handler function for delete() RPCs in the controller 58 | pub(crate) fn handle_delete(hdr: &mut RPCHeader, payload: &mut [u8]) -> Result<(), RPCError> { 59 | // Parse request 60 | let pid = match unsafe { decode::(payload) } { 61 | Some((req, _)) => req.pid, 62 | None => { 63 | log::error!("Invalid payload for request: {:?}", hdr); 64 | construct_error_ret(hdr, payload, KError::from(RPCError::MalformedRequest)); 65 | return Ok(()); 66 | } 67 | }; 68 | 69 | let ret = get_str_from_payload( 70 | payload, 71 | core::mem::size_of::(), 72 | hdr.msg_len as usize, 73 | ) 74 | .and_then(|path_string| cnrfs::MlnrKernelNode::file_delete(pid, path_string)); 75 | 76 | construct_ret(hdr, payload, ret); 77 | Ok(()) 78 | } 79 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/fileops/getinfo.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use core::fmt::Debug; 5 | 6 | use abomonation::{decode, encode, unsafe_abomonate, Abomonation}; 7 | use core2::io::Result as IOResult; 8 | use core2::io::Write; 9 | use rpc::rpc::*; 10 | 11 | use crate::error::{KError, KResult}; 12 | use crate::fallible_string::TryString; 13 | use crate::fs::cnrfs; 14 | 15 | use super::super::fileops::get_str_from_payload; 16 | use super::super::kernelrpc::*; 17 | use super::super::CLIENT_STATE; 18 | use super::FileIO; 19 | 20 | #[derive(Debug)] 21 | pub(crate) struct GetInfoReq { 22 | pub pid: usize, 23 | } 24 | unsafe_abomonate!(GetInfoReq: pid); 25 | 26 | pub(crate) fn rpc_getinfo + Debug>(pid: usize, name: P) -> KResult<(u64, u64)> { 27 | log::debug!("GetInfo({:?})", name); 28 | 29 | // Construct request data 30 | let req = GetInfoReq { pid }; 31 | let mut req_data = [0u8; core::mem::size_of::()]; 32 | unsafe { encode(&req, &mut (&mut req_data).as_mut()) } 33 | .expect("Failed to encode getinfo request"); 34 | 35 | // Construct result buffer and call RPC 36 | let mut res_data = [0u8; core::mem::size_of::>()]; 37 | CLIENT_STATE.rpc_client.lock().call( 38 | KernelRpc::GetInfo as RPCType, 39 | &[&req_data, name.as_ref()], 40 | &mut [&mut res_data], 41 | )?; 42 | 43 | // Decode and return the result 44 | if let Some((res, remaining)) = unsafe { decode::>(&mut res_data) } { 45 | if remaining.len() > 0 { 46 | Err(KError::from(RPCError::ExtraData)) 47 | } else { 48 | log::debug!("GetInfo() {:?}", res); 49 | *res 50 | } 51 | } else { 52 | Err(KError::from(RPCError::MalformedResponse)) 53 | } 54 | } 55 | 56 | // RPC Handler function for getinfo() RPCs in the controller 57 | pub(crate) fn handle_getinfo(hdr: &mut RPCHeader, payload: &mut [u8]) -> Result<(), RPCError> { 58 | // Parse request 59 | let pid = match unsafe { decode::(payload) } { 60 | Some((req, _)) => req.pid, 61 | None => { 62 | log::error!("Invalid payload for request: {:?}", hdr); 63 | construct_error_ret(hdr, payload, KError::from(RPCError::MalformedRequest)); 64 | return Ok(()); 65 | } 66 | }; 67 | 68 | let ret = get_str_from_payload( 69 | payload, 70 | core::mem::size_of::(), 71 | hdr.msg_len as usize, 72 | ) 73 | .and_then(|path_string| cnrfs::MlnrKernelNode::file_info(pid, path_string)); 74 | 75 | // Construct results from return data 76 | construct_ret(hdr, payload, ret); 77 | Ok(()) 78 | } 79 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/fileops/mkdir.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use alloc::string::String; 5 | use core::fmt::Debug; 6 | 7 | use abomonation::{decode, encode, unsafe_abomonate, Abomonation}; 8 | use core2::io::Result as IOResult; 9 | use core2::io::Write; 10 | use kpi::io::FileModes; 11 | 12 | use rpc::rpc::*; 13 | 14 | use super::super::fileops::get_str_from_payload; 15 | use super::super::kernelrpc::*; 16 | use super::super::CLIENT_STATE; 17 | use super::FileIO; 18 | use crate::error::{KError, KResult}; 19 | use crate::fallible_string::TryString; 20 | use crate::fs::cnrfs; 21 | 22 | #[derive(Debug)] 23 | pub(crate) struct MkDirReq { 24 | pub pid: usize, 25 | pub modes: FileModes, 26 | } 27 | unsafe_abomonate!(MkDirReq: pid, modes); 28 | 29 | pub(crate) fn rpc_mkdir + Debug>( 30 | pid: usize, 31 | pathname: P, 32 | modes: FileModes, 33 | ) -> KResult<(u64, u64)> { 34 | log::debug!("MkDir({:?})", pathname); 35 | 36 | // Construct request data 37 | let req = MkDirReq { pid, modes }; 38 | let mut req_data = [0u8; core::mem::size_of::()]; 39 | unsafe { encode(&req, &mut (&mut req_data).as_mut()) }.expect("Failed to encode mkdir request"); 40 | 41 | // Create result buffer 42 | let mut res_data = [0u8; core::mem::size_of::>()]; 43 | 44 | // Call RPC 45 | CLIENT_STATE.rpc_client.lock().call( 46 | KernelRpc::MkDir as RPCType, 47 | &[&req_data, pathname.as_ref()], 48 | &mut [&mut res_data], 49 | )?; 50 | 51 | // Parse and return result 52 | if let Some((res, remaining)) = unsafe { decode::>(&mut res_data) } { 53 | if remaining.len() > 0 { 54 | Err(KError::from(RPCError::ExtraData)) 55 | } else { 56 | log::debug!("MkDir() {:?}", res); 57 | *res 58 | } 59 | } else { 60 | Err(KError::from(RPCError::MalformedResponse)) 61 | } 62 | } 63 | 64 | // RPC Handler function for close() RPCs in the controller 65 | pub(crate) fn handle_mkdir(hdr: &mut RPCHeader, payload: &mut [u8]) -> Result<(), RPCError> { 66 | // Parse request 67 | let (pid, modes) = match unsafe { decode::(payload) } { 68 | Some((req, _)) => (req.pid, req.modes), 69 | None => { 70 | log::error!("Invalid payload for request: {:?}", hdr); 71 | construct_error_ret(hdr, payload, KError::from(RPCError::MalformedRequest)); 72 | return Ok(()); 73 | } 74 | }; 75 | 76 | let ret = get_str_from_payload( 77 | payload, 78 | core::mem::size_of::(), 79 | hdr.msg_len as usize, 80 | ) 81 | .and_then(|path_string| cnrfs::MlnrKernelNode::mkdir(pid, path_string, modes)); 82 | 83 | // Call mkdir function and send result 84 | construct_ret(hdr, payload, ret); 85 | Ok(()) 86 | } 87 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/fileops/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use abomonation::{unsafe_abomonate, Abomonation}; 5 | use rpc::rpc::RPCType; 6 | 7 | pub mod close; 8 | pub mod delete; 9 | pub mod getinfo; 10 | pub mod mkdir; 11 | pub mod open; 12 | pub mod rename; 13 | pub mod rw; 14 | 15 | use alloc::string::String; 16 | 17 | use crate::error::{KError, KResult}; 18 | use crate::fallible_string::TryString; 19 | 20 | #[derive(Debug, Eq, PartialEq, PartialOrd, Clone, Copy)] 21 | #[repr(u8)] 22 | pub(crate) enum FileIO { 23 | /// Create a file 24 | Create = 0, 25 | /// Open a file 26 | Open = 1, 27 | /// Read from a file 28 | Read = 2, 29 | /// Read from a file from the given offset 30 | ReadAt = 3, 31 | /// Write to a file 32 | Write = 4, 33 | /// Write to a file 34 | WriteAt = 5, 35 | /// Close an opened file. 36 | Close = 6, 37 | /// Get the information related to the file. 38 | GetInfo = 7, 39 | /// Delete the file 40 | Delete = 8, 41 | /// Write to a file without going into NR. 42 | WriteDirect = 9, 43 | /// Rename a file. 44 | FileRename = 10, 45 | /// Create a directory. 46 | MkDir = 11, 47 | 48 | Unknown = 12, 49 | } 50 | 51 | impl From for FileIO { 52 | /// Construct a RPCType enum based on a 8-bit value. 53 | fn from(op: RPCType) -> FileIO { 54 | match op { 55 | 0 => FileIO::Create, 56 | 1 => FileIO::Open, 57 | 2 => FileIO::Read, 58 | 3 => FileIO::ReadAt, 59 | 4 => FileIO::Write, 60 | 5 => FileIO::WriteAt, 61 | 6 => FileIO::Close, 62 | 7 => FileIO::GetInfo, 63 | 8 => FileIO::Delete, 64 | 9 => FileIO::WriteDirect, 65 | 10 => FileIO::FileRename, 66 | 11 => FileIO::MkDir, 67 | _ => FileIO::Unknown, 68 | } 69 | } 70 | } 71 | unsafe_abomonate!(FileIO); 72 | 73 | pub(crate) fn get_str_from_payload( 74 | payload: &mut [u8], 75 | start: usize, 76 | end: usize, 77 | ) -> KResult { 78 | core::str::from_utf8(&payload[start..end]) 79 | .map_err(|e| KError::from(e)) 80 | .and_then(|str_from_utf8| TryString::try_from(str_from_utf8).map_err(|e| KError::from(e))) 81 | .and_then(|parsed_str| Ok(parsed_str.try_into().unwrap())) // Okay to unwrap, should be infallable 82 | } 83 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | #![allow(warnings)] 5 | 6 | use static_assertions as sa; 7 | 8 | use rpc::server::{RPCHandler, RegistrationHandler}; 9 | 10 | use crate::memory::{mcache::MCache, LARGE_PAGE_SIZE}; 11 | 12 | pub(crate) mod client_state; 13 | pub(crate) mod controller; 14 | pub(crate) mod controller_state; 15 | pub(crate) mod dcm; 16 | pub(crate) mod fileops; 17 | pub(crate) mod get_shmem_frames; 18 | pub(crate) mod get_shmem_structure; 19 | pub(crate) mod kernelrpc; 20 | pub(crate) mod processops; 21 | pub(crate) mod registration; 22 | pub(crate) mod syscalls; 23 | pub(crate) mod systemops; 24 | 25 | pub(crate) use self::kernelrpc::KernelRpc; 26 | 27 | pub(crate) use self::client_state::CLIENT_STATE; 28 | 29 | use self::registration::register_client; 30 | 31 | // Re-export client registration 32 | pub(crate) const CLIENT_REGISTRAR: RegistrationHandler = register_client; 33 | 34 | // Re-export handlers: file operations 35 | pub(crate) const CLOSE_HANDLER: RPCHandler = fileops::close::handle_close; 36 | pub(crate) const DELETE_HANDLER: RPCHandler = fileops::delete::handle_delete; 37 | pub(crate) const GETINFO_HANDLER: RPCHandler = fileops::getinfo::handle_getinfo; 38 | pub(crate) const MKDIR_HANDLER: RPCHandler = fileops::mkdir::handle_mkdir; 39 | pub(crate) const OPEN_HANDLER: RPCHandler = fileops::open::handle_open; 40 | pub(crate) const RENAME_HANDLER: RPCHandler = fileops::rename::handle_rename; 41 | pub(crate) const READ_HANDLER: RPCHandler = fileops::rw::handle_read; 42 | pub(crate) const WRITE_HANDLER: RPCHandler = fileops::rw::handle_write; 43 | 44 | // Re-export handdlers: process operations 45 | pub(crate) const REQUEST_CORE_HANDLER: RPCHandler = processops::request_core::handle_request_core; 46 | pub(crate) const RELEASE_CORE_HANDLER: RPCHandler = processops::release_core::handle_release_core; 47 | pub(crate) const ALLOCATE_PHYSICAL_HANDLER: RPCHandler = 48 | processops::allocate_physical::handle_allocate_physical; 49 | pub(crate) const RELEASE_PHYSICAL_HANDLER: RPCHandler = 50 | processops::release_physical::handle_release_physical; 51 | pub(crate) const LOG_HANDLER: RPCHandler = processops::print::handle_log; 52 | 53 | // Re-export handlers: system operations 54 | pub(crate) const GET_HARDWARE_THREADS_HANDLER: RPCHandler = 55 | systemops::get_hardware_threads::handle_get_hardware_threads; 56 | 57 | // there aren't syscalls, but are other operations 58 | pub(crate) const GET_SHMEM_STRUCTURE_HANDLER: RPCHandler = 59 | get_shmem_structure::handle_get_shmem_structure; 60 | pub(crate) const GET_SHMEM_FRAMES_HANDLER: RPCHandler = get_shmem_frames::handle_get_shmem_frames; 61 | 62 | /// A cache of base pages 63 | /// TODO(rackscale): think about how we should constrain this? 64 | /// 65 | /// Used locally on the client, since only large pages are allocated by the controller. 66 | pub(crate) type FrameCacheBase = MCache<2048, 0>; 67 | sa::const_assert!(core::mem::size_of::() <= LARGE_PAGE_SIZE); 68 | sa::const_assert!(core::mem::align_of::() <= LARGE_PAGE_SIZE); 69 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/processops/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | pub mod allocate_physical; 5 | pub mod print; 6 | pub mod release_core; 7 | pub mod release_physical; 8 | pub mod request_core; 9 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/processops/print.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 University of Colorado and VMware Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | use core::fmt::Debug; 4 | 5 | use abomonation::{decode, encode, unsafe_abomonate, Abomonation}; 6 | use alloc::string::String; 7 | use core2::io::Result as IOResult; 8 | use core2::io::Write; 9 | 10 | use klogger::sprint; 11 | use kpi::system::MachineId; 12 | use rpc::rpc::*; 13 | 14 | use super::super::kernelrpc::*; 15 | use super::super::CLIENT_STATE; 16 | use crate::arch::serial::SerialControl; 17 | use crate::error::{KError, KResult}; 18 | use crate::fallible_string::TryString; 19 | 20 | #[derive(Debug)] 21 | pub(crate) struct LogReq { 22 | pub mid: MachineId, 23 | } 24 | unsafe_abomonate!(LogReq: mid); 25 | 26 | pub(crate) fn rpc_log(msg: String) -> KResult<(u64, u64)> { 27 | if let Some(print_str) = SerialControl::buffered_print_and_return(&msg) { 28 | // Construct request data 29 | let req = LogReq { 30 | mid: *crate::environment::MACHINE_ID, 31 | }; 32 | let mut req_data = [0u8; core::mem::size_of::()]; 33 | unsafe { encode(&req, &mut (&mut req_data).as_mut()) } 34 | .expect("Failed to encode log request"); 35 | 36 | // Construct result buffer and call RPC 37 | let mut res_data = [0u8; core::mem::size_of::>()]; 38 | CLIENT_STATE.rpc_client.lock().call( 39 | KernelRpc::Log as RPCType, 40 | &[&req_data, print_str.as_ref()], 41 | &mut [&mut res_data], 42 | )?; 43 | 44 | // Decode and return the result 45 | if let Some((res, remaining)) = unsafe { decode::>(&mut res_data) } { 46 | if remaining.len() > 0 { 47 | log::error!("Log() RPC failed"); 48 | Err(KError::from(RPCError::ExtraData)) 49 | } else { 50 | *res 51 | } 52 | } else { 53 | Err(KError::from(RPCError::MalformedResponse)) 54 | } 55 | } else { 56 | Ok((0, 0)) 57 | } 58 | } 59 | 60 | // RPC Handler function for log() RPCs in the controller 61 | pub(crate) fn handle_log(hdr: &mut RPCHeader, mut payload: &mut [u8]) -> Result<(), RPCError> { 62 | // Decode and return the result 63 | if let Some((res, remaining)) = unsafe { decode::(&mut payload) } { 64 | match core::str::from_utf8( 65 | &remaining[0..(hdr.msg_len as usize - core::mem::size_of::())], 66 | ) { 67 | Ok(msg_str) => log::info!("RemoteLog({}) {}", res.mid, msg_str), 68 | Err(e) => log::error!( 69 | "log: invalid UTF-8 string: {:?}", 70 | &payload[0..hdr.msg_len as usize] 71 | ), 72 | } 73 | } 74 | 75 | // Construct results from return data 76 | construct_ret(hdr, payload, Ok((0, 0))); 77 | Ok(()) 78 | } 79 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/rackscale/systemops/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | pub mod get_hardware_threads; 5 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/signals.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Platform specific functions to deal with CNR 5 | 6 | pub(crate) fn advance_replica(mtid: kpi::system::MachineThreadId, log_id: usize) { 7 | super::tlb::advance_replica(mtid, log_id) 8 | } 9 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/timer.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Timer API 5 | 6 | use apic::ApicDriver; 7 | 8 | /// Default when to raise the next timer irq (in rdtsc ticks) 9 | pub(crate) const DEFAULT_TIMER_DEADLINE: u64 = 2_000_000_000; 10 | 11 | /// Register a periodic timer to advance replica 12 | /// 13 | /// TODO(api): Ideally this should come from Instant::now() + 14 | /// Duration::from_millis(10) and for that we need a way to reliably 15 | /// convert between TSC and Instant 16 | pub(crate) fn set(deadline: u64) { 17 | let mut apic = super::irq::LOCAL_APIC.borrow_mut(); 18 | apic.tsc_enable(); 19 | unsafe { apic.tsc_set(x86::time::rdtsc() + deadline) }; 20 | } 21 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/x86_64-nrk.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": "", 3 | "dynamic-linking": false, 4 | "llvm-target": "x86_64-unknown-none", 5 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", 6 | "target-endian": "little", 7 | "target-pointer-width": "64", 8 | "target-c-int-width": "32", 9 | "linker": "ld", 10 | "linker-flavor": "ld", 11 | "os": "none", 12 | "arch": "x86_64", 13 | "disable-redzone": true, 14 | "features": "+sse", 15 | "position-independent-executables": true, 16 | "executables": true, 17 | "has-thread-local": true 18 | } -------------------------------------------------------------------------------- /kernel/src/environment.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use log::trace; 5 | use spin::Lazy; 6 | 7 | use kpi::system::new_gtid; 8 | 9 | use crate::arch::{MAX_CORES, MAX_MACHINES, MAX_NUMA_NODES}; 10 | 11 | /// The core id of the current core (hardware thread). 12 | #[thread_local] 13 | pub(crate) static CORE_ID: Lazy = 14 | Lazy::new(|| new_gtid(atopology::MACHINE_TOPOLOGY.current_thread().id, *MACHINE_ID)); 15 | 16 | /// The NUMA node id of the current core (hardware thread). 17 | #[thread_local] 18 | pub(crate) static NODE_ID: Lazy = Lazy::new(|| { 19 | atopology::MACHINE_TOPOLOGY 20 | .current_thread() 21 | .node_id 22 | .unwrap_or(0) 23 | }); 24 | 25 | /// The machine id of the current host. 26 | pub(crate) static MACHINE_ID: Lazy = 27 | Lazy::new(|| crate::CMDLINE.get().map_or(0, |c| c.machine_id)); 28 | 29 | /// Number of machines in the current deployment. 30 | pub(crate) static NUM_MACHINES: Lazy = 31 | Lazy::new(|| crate::CMDLINE.get().map_or(1, |c| c.workers) as usize); 32 | 33 | /// How many cores (hardware threads) we have per NUMA node. 34 | pub(crate) static CORES_PER_NUMA_NODE: Lazy = 35 | Lazy::new(|| match atopology::MACHINE_TOPOLOGY.nodes().next() { 36 | Some(node) => node.threads().count(), 37 | None => 1, 38 | }); 39 | 40 | /// Initialize the machine topology (needs ACPI and alloc): 41 | pub fn init_topology() { 42 | lazy_static::initialize(&atopology::MACHINE_TOPOLOGY); 43 | log::info!("Topology parsed"); 44 | 45 | trace!("{:#?}", *atopology::MACHINE_TOPOLOGY); 46 | let nodes = atopology::MACHINE_TOPOLOGY.num_nodes(); 47 | let cores = atopology::MACHINE_TOPOLOGY.num_threads(); 48 | assert!( 49 | MAX_NUMA_NODES >= nodes, 50 | "We don't support more NUMA nodes than `MAX_NUMA_NODES." 51 | ); 52 | assert!( 53 | MAX_CORES >= cores, 54 | "We don't support more cores than `MAX_CORES." 55 | ); 56 | assert!( 57 | cnr::MAX_REPLICAS_PER_LOG >= nodes, 58 | "We don't support as many replicas as we have NUMA nodes." 59 | ); 60 | assert!( 61 | node_replication::MAX_REPLICAS_PER_LOG >= nodes, 62 | "We don't support as many replicas as we have NUMA nodes." 63 | ); 64 | assert!( 65 | MAX_MACHINES >= *NUM_MACHINES, 66 | "We don't support more machines than `MAX_MACHINES`" 67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /kernel/src/fallible_string.rs: -------------------------------------------------------------------------------- 1 | //! Implement Fallible String 2 | //! 3 | //! Thils file will ideally added to the fallible_collections library. 4 | 5 | use alloc::collections::TryReserveError; 6 | use alloc::string::String; 7 | 8 | /// trait implementing all fallible methods on vec 9 | pub(crate) trait FallibleString { 10 | /// see with_capacity 11 | fn try_with_capacity(capacity: usize) -> Result; 12 | /// see push 13 | fn try_push(&mut self, ch: char) -> Result<(), TryReserveError>; 14 | /// see push_str 15 | fn try_push_str(&mut self, string: &str) -> Result<(), TryReserveError>; 16 | } 17 | 18 | impl FallibleString for String { 19 | #[inline] 20 | fn try_with_capacity(capacity: usize) -> Result { 21 | let mut s = String::new(); 22 | s.try_reserve(capacity)?; 23 | Ok(s) 24 | } 25 | 26 | #[inline] 27 | fn try_push(&mut self, ch: char) -> Result<(), TryReserveError> { 28 | self.try_reserve(1)?; 29 | self.push(ch); 30 | Ok(()) 31 | } 32 | 33 | #[inline] 34 | fn try_push_str(&mut self, string: &str) -> Result<(), TryReserveError> { 35 | self.try_reserve(string.len())?; 36 | self.push_str(string); 37 | Ok(()) 38 | } 39 | } 40 | 41 | /// TryString is a thin wrapper around String to provide support for fallible 42 | /// allocation. 43 | /// 44 | /// See the crate documentation for more. 45 | #[derive(PartialEq)] 46 | pub(crate) struct TryString { 47 | inner: String, 48 | } 49 | 50 | impl From for String { 51 | fn from(s: TryString) -> String { 52 | s.inner 53 | } 54 | } 55 | 56 | impl core::convert::TryFrom<&str> for TryString { 57 | type Error = TryReserveError; 58 | 59 | #[inline] 60 | fn try_from(value: &str) -> Result { 61 | let mut inner = String::new(); 62 | inner.try_reserve(value.len())?; 63 | inner.push_str(value); 64 | Ok(TryString { inner }) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /kernel/src/memory/shmem_affinity.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 VMware, Inc. and University of Colorado Boulder. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | //! Code to support allocation by shared memory affinity. 4 | //! 5 | //! Defines affinitys for 1 shmem region per machine in rackscale 6 | //! deployment. 7 | 8 | use atopology::NodeId; 9 | use kpi::system::MachineId; 10 | 11 | use crate::arch::MAX_NUMA_NODES; 12 | 13 | #[allow(unused)] 14 | #[inline(always)] 15 | pub(crate) fn is_shmem_affinity(affinity: NodeId) -> bool { 16 | affinity >= MAX_NUMA_NODES 17 | } 18 | 19 | /// Get the id of the shmem region 20 | #[allow(unused)] 21 | #[inline(always)] 22 | pub(crate) fn mid_to_shmem_affinity(mid: MachineId) -> NodeId { 23 | // shmem regions are placed after local numa, so offset by MAX_NUMA_NODES 24 | MAX_NUMA_NODES + (mid as NodeId) 25 | } 26 | 27 | #[allow(unused)] 28 | #[inline(always)] 29 | pub(crate) fn shmem_affinity_to_mid(affinity: NodeId) -> MachineId { 30 | // shmem regions are placed after local numa, so offset by MAX_NUMA_NODES 31 | affinity - MAX_NUMA_NODES 32 | } 33 | 34 | #[allow(unused)] 35 | #[inline(always)] 36 | pub(crate) fn local_shmem_affinity() -> NodeId { 37 | mid_to_shmem_affinity(*crate::environment::MACHINE_ID) 38 | } 39 | -------------------------------------------------------------------------------- /kernel/src/memory/shmemalloc.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 University of Colorado and VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! A stub of a memory provider that queries DCM for memory. If it fails, 5 | //! it should cause the replica to drop (eventually) 6 | 7 | use alloc::alloc::{alloc, dealloc}; 8 | use core::alloc::Layout; 9 | use core::alloc::{AllocError, Allocator}; 10 | use core::ptr::NonNull; 11 | 12 | use atopology::NodeId; 13 | 14 | use super::shmem_affinity::{is_shmem_affinity, shmem_affinity_to_mid}; 15 | use crate::arch::kcb::per_core_mem; 16 | 17 | #[derive(Clone)] 18 | pub(crate) struct ShmemAlloc { 19 | pub(crate) affinity: NodeId, 20 | } 21 | 22 | impl ShmemAlloc { 23 | pub(crate) fn new(affinity: NodeId) -> ShmemAlloc { 24 | assert!( 25 | is_shmem_affinity(affinity) 26 | && shmem_affinity_to_mid(affinity) < *crate::environment::NUM_MACHINES 27 | ); 28 | ShmemAlloc { affinity } 29 | } 30 | } 31 | 32 | unsafe impl Allocator for ShmemAlloc { 33 | fn allocate(&self, layout: Layout) -> Result, AllocError> { 34 | log::trace!("ShmemAlloc - allocating"); 35 | let affinity = { 36 | // We want to allocate the logs in shared memory 37 | let pcm = per_core_mem(); 38 | let affinity = pcm.physical_memory.borrow().affinity; 39 | pcm.set_mem_affinity(self.affinity) 40 | .expect("Can't change affinity"); 41 | affinity 42 | }; 43 | 44 | let ptr = unsafe { alloc(layout) }; 45 | 46 | let ret = if !ptr.is_null() { 47 | Ok(unsafe { 48 | let nptr = NonNull::new_unchecked(ptr); 49 | NonNull::slice_from_raw_parts(nptr, layout.size()) 50 | }) 51 | } else { 52 | Err(AllocError) 53 | }; 54 | 55 | // Return to previous affinity 56 | let pcm = per_core_mem(); 57 | pcm.set_mem_affinity(affinity) 58 | .expect("Can't change affinity"); 59 | 60 | log::trace!("ShmemAlloc - allocating finished."); 61 | ret 62 | } 63 | 64 | unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { 65 | let affinity = { 66 | // We want to allocate the logs in shared memory 67 | let pcm = per_core_mem(); 68 | let affinity = pcm.physical_memory.borrow().affinity; 69 | pcm.set_mem_affinity(self.affinity) 70 | .expect("Can't change affinity"); 71 | affinity 72 | }; 73 | 74 | // dealloc just goes to the underlying allocator 75 | dealloc(ptr.as_ptr(), layout); 76 | 77 | // Return to previous affinity 78 | let pcm = per_core_mem(); 79 | pcm.set_mem_affinity(affinity) 80 | .expect("Can't change affinity"); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /kernel/src/memory/utils.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Utility code for dealing with memory / bytes etc. 5 | 6 | use core::fmt; 7 | 8 | use super::{BASE_PAGE_SIZE, LARGE_PAGE_SIZE}; 9 | 10 | /// Calculate how many base and large pages we need to fit a given size. 11 | /// 12 | /// # Returns 13 | /// - A tuple containing (base-pages, large-pages). 14 | /// - base-pages will never exceed LARGE_PAGE_SIZE / BASE_PAGE_SIZE. 15 | pub(crate) fn size_to_pages(size: usize) -> (usize, usize) { 16 | let bytes_not_in_large = size % LARGE_PAGE_SIZE; 17 | 18 | let div = bytes_not_in_large / BASE_PAGE_SIZE; 19 | let rem = bytes_not_in_large % BASE_PAGE_SIZE; 20 | let base_pages = if rem > 0 { div + 1 } else { div }; 21 | 22 | let remaining_size = size - bytes_not_in_large; 23 | let div = remaining_size / LARGE_PAGE_SIZE; 24 | let rem = remaining_size % LARGE_PAGE_SIZE; 25 | let large_pages = if rem > 0 { div + 1 } else { div }; 26 | 27 | (base_pages, large_pages) 28 | } 29 | 30 | /// Human-readable representation of a data-size. 31 | /// 32 | /// # Notes 33 | /// Use for pretty printing and debugging only. 34 | #[derive(PartialEq)] 35 | pub(crate) enum DataSize { 36 | Bytes(f64), 37 | KiB(f64), 38 | MiB(f64), 39 | GiB(f64), 40 | } 41 | 42 | impl DataSize { 43 | /// Construct a new DataSize passing the amount of `bytes` 44 | /// we want to convert 45 | pub(crate) fn from_bytes(bytes: usize) -> DataSize { 46 | if bytes < 1024 { 47 | DataSize::Bytes(bytes as f64) 48 | } else if bytes < (1024 * 1024) { 49 | DataSize::KiB(bytes as f64 / 1024.0) 50 | } else if bytes < (1024 * 1024 * 1024) { 51 | DataSize::MiB(bytes as f64 / (1024 * 1024) as f64) 52 | } else { 53 | DataSize::GiB(bytes as f64 / (1024 * 1024 * 1024) as f64) 54 | } 55 | } 56 | 57 | /// Write rounded size and SI unit to `f` 58 | fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { 59 | match self { 60 | DataSize::Bytes(n) => write!(f, "{:.2} B", n), 61 | DataSize::KiB(n) => write!(f, "{:.2} KiB", n), 62 | DataSize::MiB(n) => write!(f, "{:.2} MiB", n), 63 | DataSize::GiB(n) => write!(f, "{:.2} GiB", n), 64 | } 65 | } 66 | } 67 | 68 | impl fmt::Debug for DataSize { 69 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 70 | self.format(f) 71 | } 72 | } 73 | 74 | impl fmt::Display for DataSize { 75 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 76 | self.format(f) 77 | } 78 | } 79 | 80 | #[cfg(test)] 81 | mod tests { 82 | use super::*; 83 | use crate::memory::{BASE_PAGE_SIZE, LARGE_PAGE_SIZE}; 84 | 85 | #[test] 86 | fn size_formatting() { 87 | let ds = DataSize::from_bytes(LARGE_PAGE_SIZE); 88 | assert_eq!(ds, DataSize::MiB(2.0)); 89 | 90 | let ds = DataSize::from_bytes(BASE_PAGE_SIZE); 91 | assert_eq!(ds, DataSize::KiB(4.0)); 92 | 93 | let ds = DataSize::from_bytes(1024 * LARGE_PAGE_SIZE); 94 | assert_eq!(ds, DataSize::GiB(2.0)); 95 | 96 | let ds = DataSize::from_bytes(usize::MIN); 97 | assert_eq!(ds, DataSize::Bytes(0.0)); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /kernel/src/pci.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | #![allow(unused)] 5 | 6 | use alloc::vec::Vec; 7 | use arrayvec::ArrayVec; 8 | use driverkit::pci::{scan_bus, PciDevice}; 9 | use fallible_collections::FallibleVecGlobal; 10 | use lazy_static::lazy_static; 11 | use log::info; 12 | use spin::Mutex; 13 | 14 | use crate::environment; 15 | 16 | /// The maximum number of PCI devices we support on the machine. 17 | /// 18 | /// This is a constant, and is used to allocate a static array. 19 | /// Maybe this can be dynamic in the future. 20 | pub(crate) const MAX_PCI_DEVICES: usize = 24; 21 | 22 | lazy_static! { 23 | /// All PCI devices found on the machine. 24 | pub(crate) static ref PCI_DEVICES: ArrayVec>, MAX_PCI_DEVICES> = { 25 | let mut devices = ArrayVec::new(); 26 | let bus_iter = scan_bus(); 27 | for device in bus_iter { 28 | info!("PCI: {}", device); 29 | devices.push(Mutex::new(Some(device))); 30 | } 31 | 32 | devices 33 | }; 34 | } 35 | 36 | /// Takes a device (for use in a driver). 37 | pub(crate) fn claim_device(vendor_id: u16, device_id: u16) -> Option { 38 | for device in PCI_DEVICES.iter() { 39 | let device = &mut *device.lock(); 40 | if let Some(locked_device) = device { 41 | if locked_device.vendor_id() == vendor_id && locked_device.device_id() == device_id { 42 | return device.take(); 43 | } 44 | } 45 | } 46 | None 47 | } 48 | 49 | /// Takes multiple devices (for use in a driver). 50 | pub(crate) fn claim_devices(vendor_id: u16, device_id: u16) -> Vec { 51 | let mut devices = Vec::try_with_capacity(MAX_PCI_DEVICES).expect("Failed to alloc memory"); 52 | for device in PCI_DEVICES.iter() { 53 | let device = &mut *device.lock(); 54 | if let Some(locked_device) = device { 55 | if locked_device.vendor_id() == vendor_id && locked_device.device_id() == device_id { 56 | if let Some(mydevice) = device.take() { 57 | devices.push(mydevice); 58 | } 59 | } 60 | } 61 | } 62 | devices 63 | } 64 | 65 | pub(crate) fn init() { 66 | lazy_static::initialize(&PCI_DEVICES); 67 | } 68 | -------------------------------------------------------------------------------- /kernel/src/transport/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | #[cfg(feature = "ethernet")] 5 | pub mod ethernet; 6 | #[cfg(feature = "shmem")] 7 | pub mod shmem; 8 | -------------------------------------------------------------------------------- /kernel/tests/dhcpd.conf: -------------------------------------------------------------------------------- 1 | # option definitions common to all supported networks... 2 | option domain-name "bkern.com"; 3 | option domain-name-servers ns1.example.org, ns2.example.org; 4 | 5 | ddns-update-style none; 6 | 7 | subnet 172.31.0.0 netmask 255.255.255.0 { 8 | range 172.31.0.12 172.31.0.16; 9 | option routers 172.31.0.20; 10 | option subnet-mask 255.255.255.0; 11 | default-lease-time 1; 12 | max-lease-time 1; 13 | } 14 | 15 | host nrk1 { 16 | hardware ethernet 56:b4:44:e9:62:d0; 17 | fixed-address 172.31.0.10; 18 | } 19 | 20 | host nrk2 { 21 | hardware ethernet 56:b4:44:e9:62:d1; 22 | fixed-address 172.31.0.11; 23 | } -------------------------------------------------------------------------------- /kernel/tests/s05_user_app_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! A set of integration tests to ensure OS functionality is as expected. 5 | //! These tests spawn a QEMU instance and run the OS on it. 6 | //! The output from serial/QEMU is parsed and verified for expected output. 7 | //! 8 | //! The naming scheme of the tests ensures a somewhat useful order of test 9 | //! execution taking into account the dependency chain: 10 | //! * `s05_*`: User-space applications 11 | 12 | use rexpect::errors::*; 13 | use rexpect::process::signal::SIGTERM; 14 | use rexpect::process::wait::WaitStatus; 15 | 16 | use testutils::builder::BuildArgs; 17 | use testutils::helpers::{setup_network, spawn_dhcpd, spawn_nc, spawn_nrk, DHCP_ACK_MATCH}; 18 | use testutils::redis::{REDIS_BENCHMARK, REDIS_PORT, REDIS_START_MATCH}; 19 | use testutils::runner_args::{wait_for_sigterm, RunnerArgs}; 20 | 21 | /// Tests that user-space application redis is functional 22 | /// by spawing it and connecting to it from the network. 23 | /// 24 | /// This tests various user-space components such as: 25 | /// * Build and linking of user-space libraries 26 | /// * BSD libOS network stack, libc and pthreads 27 | /// * PCI/user-space drivers 28 | /// * Interrupt registration and upcalls 29 | /// * (kernel memfs eventually for DB persistence) 30 | //#[cfg(not(feature = "baremetal"))] 31 | //#[test] 32 | #[allow(unused)] 33 | fn s05_redis_smoke() { 34 | let _r = which::which(REDIS_BENCHMARK) 35 | .expect("redis-benchmark not installed on host, test will fail!"); 36 | 37 | setup_network(1); 38 | 39 | let build = BuildArgs::default() 40 | .module("rkapps") 41 | .user_feature("rkapps:redis") 42 | .build(); 43 | let cmdline = RunnerArgs::new_with_build("userspace", &build) 44 | .cmd("init=redis.bin") 45 | .timeout(20_000); 46 | 47 | let mut output = String::new(); 48 | let mut qemu_run = || -> Result { 49 | let mut dhcp_server = spawn_dhcpd()?; 50 | let mut p = spawn_nrk(&cmdline)?; 51 | 52 | // Test that DHCP works: 53 | dhcp_server.exp_regex(DHCP_ACK_MATCH)?; 54 | output += p.exp_string(REDIS_START_MATCH)?.as_str(); 55 | 56 | std::thread::sleep(std::time::Duration::from_secs(6)); 57 | 58 | let mut redis_client = spawn_nc(REDIS_PORT)?; 59 | // Test that redis commands work as expected: 60 | redis_client.send_line("ping")?; 61 | redis_client.exp_string("+PONG")?; 62 | redis_client.send_line("set msg \"Hello, World!\"")?; 63 | redis_client.exp_string("+OK")?; 64 | redis_client.send_line("get msg")?; 65 | redis_client.exp_string("$13")?; 66 | redis_client.exp_string("Hello, World!")?; 67 | 68 | // We can get the key--value pair with a second client too: 69 | let mut redis_client2 = spawn_nc(REDIS_PORT)?; 70 | redis_client2.send_line("get msg")?; 71 | redis_client2.exp_string("$13")?; 72 | redis_client2.exp_string("Hello, World!")?; 73 | 74 | dhcp_server.send_control('c')?; 75 | redis_client.process.kill(SIGTERM)?; 76 | p.process.kill(SIGTERM) 77 | }; 78 | 79 | wait_for_sigterm(&cmdline, qemu_run(), output); 80 | } 81 | -------------------------------------------------------------------------------- /kernel/testutils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "testutils" 3 | version = "0.0.1" 4 | authors = [ 5 | "Gerd Zellweger ", 6 | ] 7 | description = "Experimental OS kernel test utility code" 8 | license = "MIT OR Apache-2.0" 9 | build = "build.rs" 10 | edition = "2021" 11 | resolver = "2" 12 | 13 | [build-dependencies] 14 | cc = "1.0" 15 | 16 | [dependencies] 17 | csv = "1.1" 18 | env_logger = "0.9" 19 | hwloc2 = "2.2" 20 | lazy_static = { version = "1.4", features = ["spin_no_std"] } 21 | serde = { version = "1" } 22 | memfile = "0.2.1" 23 | rexpect = { git = "https://github.com/gz/rexpect.git", branch = "eof-nix" } -------------------------------------------------------------------------------- /kernel/testutils/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | extern crate cc; 4 | 5 | use std::process::Command; 6 | 7 | fn main() { 8 | let output = Command::new("git") 9 | .args(&["rev-parse", "HEAD"]) 10 | .output() 11 | .expect("Could not determine git hash"); 12 | let git_hash = String::from_utf8(output.stdout).expect("Could not parse the git hash"); 13 | println!("cargo:rustc-env=GIT_HASH={}", git_hash); 14 | } 15 | -------------------------------------------------------------------------------- /lib/apic/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled files 2 | *.o 3 | *.so 4 | *.rlib 5 | *.dll 6 | 7 | # Executables 8 | *.exe 9 | 10 | # Generated by Cargo 11 | /target/ 12 | Cargo.lock -------------------------------------------------------------------------------- /lib/apic/.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: nightly -------------------------------------------------------------------------------- /lib/apic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "apic" 3 | version = "0.0.1" 4 | authors = ["Gerd Zellweger "] 5 | description = "ACPI drivers." 6 | readme = "README.md" 7 | license = "MIT OR Apache-2.0" 8 | keywords = ["os", "acpi", "irq", "driver", "x86"] 9 | edition = "2018" 10 | 11 | [dependencies] 12 | driverkit = "0.24" 13 | x86 = { version = "0.52", features = ["unstable"] } 14 | log = "0.4" 15 | bitflags = "1.0" 16 | bit_field = "0.10.0" 17 | 18 | [target.'cfg(unix)'.dev-dependencies] 19 | env_logger = "0.5" 20 | -------------------------------------------------------------------------------- /lib/apic/README.md: -------------------------------------------------------------------------------- 1 | # APIC driver 2 | 3 | APIC driver for nrk. -------------------------------------------------------------------------------- /lib/apic/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | #![no_std] 5 | #![feature(core_intrinsics)] 6 | 7 | use x86::apic::{ApicId, Icr}; 8 | 9 | pub const TSC_TIMER_VECTOR: u8 = 252; 10 | 11 | pub mod x2apic; 12 | pub mod xapic; 13 | 14 | /// Abstracts common interface of local APIC (x2APIC, xAPIC) drivers. 15 | pub trait ApicDriver { 16 | /// Is a bootstrap processor? 17 | fn bsp(&self) -> bool; 18 | 19 | /// Return APIC ID. 20 | fn id(&self) -> u32; 21 | 22 | /// Return the logical APIC ID. 23 | fn logical_id(&self) -> u32; 24 | 25 | /// Read APIC version 26 | fn version(&self) -> u32; 27 | 28 | /// End Of Interrupt -- Acknowledge interrupt delivery. 29 | fn eoi(&mut self); 30 | 31 | /// Enable TSC deadline timer. 32 | fn tsc_enable(&mut self); 33 | 34 | /// Set TSC deadline value. 35 | fn tsc_set(&self, value: u64); 36 | 37 | /// Send a INIT IPI to a core. 38 | /// 39 | /// # Safety 40 | /// This can reset a core. 41 | unsafe fn ipi_init(&mut self, core: ApicId); 42 | 43 | /// Deassert INIT IPI. 44 | /// 45 | /// # Safety 46 | /// This can reset a core. 47 | unsafe fn ipi_init_deassert(&mut self); 48 | 49 | /// Send a STARTUP IPI to a core. 50 | /// 51 | /// # Safety 52 | /// This can reset a core. 53 | unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8); 54 | 55 | /// Send a generic IPI. 56 | /// 57 | /// # Safety 58 | /// Triggers an IPI on a remote core(s) and can easily crash them by sending 59 | /// to the wrong core, or the wrong vector etc. 60 | unsafe fn send_ipi(&mut self, icr: Icr); 61 | } 62 | -------------------------------------------------------------------------------- /lib/apic/src/x2apic.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use log::trace; 5 | 6 | use driverkit::{DriverControl, DriverState}; 7 | use x86::apic::x2apic::X2APIC; 8 | use x86::apic::{ApicControl, ApicId, Icr}; 9 | 10 | /// An x2APIC driver 11 | #[derive(Debug)] 12 | pub struct X2APICDriver { 13 | timer_vector: u8, 14 | state: DriverState, 15 | inner: X2APIC, 16 | } 17 | 18 | impl Default for X2APICDriver { 19 | /// Create a new x2APIC driver object. 20 | fn default() -> Self { 21 | Self { 22 | timer_vector: crate::TSC_TIMER_VECTOR, 23 | state: DriverState::Uninitialized, 24 | inner: X2APIC::new(), 25 | } 26 | } 27 | } 28 | 29 | impl X2APICDriver { 30 | pub const fn new() -> Self { 31 | Self { 32 | timer_vector: crate::TSC_TIMER_VECTOR, 33 | state: DriverState::Uninitialized, 34 | inner: X2APIC::new(), 35 | } 36 | } 37 | } 38 | 39 | impl crate::ApicDriver for X2APICDriver { 40 | /// Is a bootstrap processor? 41 | fn bsp(&self) -> bool { 42 | self.inner.bsp() 43 | } 44 | 45 | /// Return APIC ID. 46 | fn id(&self) -> u32 { 47 | self.inner.id() 48 | } 49 | 50 | /// Return the logical APIC ID. 51 | fn logical_id(&self) -> u32 { 52 | self.inner.logical_id() 53 | } 54 | 55 | /// Read APIC version 56 | fn version(&self) -> u32 { 57 | self.inner.version() 58 | } 59 | 60 | /// End Of Interrupt -- Acknowledge interrupt delivery. 61 | fn eoi(&mut self) { 62 | self.inner.eoi() 63 | } 64 | 65 | /// Enable TSC deadline timer. 66 | fn tsc_enable(&mut self) { 67 | self.inner.tsc_enable(self.timer_vector) 68 | } 69 | 70 | /// Set TSC deadline value. 71 | fn tsc_set(&self, value: u64) { 72 | self.inner.tsc_set(value) 73 | } 74 | 75 | /// Send a INIT IPI to a core. 76 | unsafe fn ipi_init(&mut self, core: ApicId) { 77 | self.inner.ipi_init(core) 78 | } 79 | 80 | /// Deassert INIT IPI. 81 | unsafe fn ipi_init_deassert(&mut self) { 82 | self.inner.ipi_init_deassert() 83 | } 84 | 85 | /// Send a STARTUP IPI to a core. 86 | unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8) { 87 | self.inner.ipi_startup(core, start_page) 88 | } 89 | 90 | /// Send a generic IPI. 91 | unsafe fn send_ipi(&mut self, icr: Icr) { 92 | trace!("sending icr {:?}", icr); 93 | self.inner.send_ipi(icr) 94 | } 95 | } 96 | 97 | impl DriverControl for X2APICDriver { 98 | /// Attach to the device 99 | fn attach(&mut self) { 100 | self.set_state(DriverState::Attached(0)); 101 | self.inner.attach(); 102 | } 103 | 104 | /// Detach from the device 105 | fn detach(&mut self) { 106 | self.inner.detach(); 107 | self.set_state(DriverState::Detached); 108 | } 109 | 110 | /// Destroy the device. 111 | fn destroy(mut self) { 112 | self.detach(); 113 | self.set_state(DriverState::Destroyed); 114 | } 115 | 116 | /// Query driver state 117 | fn state(&self) -> DriverState { 118 | self.state 119 | } 120 | 121 | /// Set the state of the driver 122 | fn set_state(&mut self, st: DriverState) { 123 | self.state = st; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /lib/apic/src/xapic.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use x86::apic::xapic::XAPIC; 5 | use x86::apic::{ApicControl, ApicId, Icr}; 6 | 7 | use driverkit::{DriverControl, DriverState}; 8 | 9 | /// A device driver for an XAPIC. 10 | #[derive(Debug)] 11 | pub struct XAPICDriver { 12 | timer_vector: u8, 13 | inner: XAPIC, 14 | state: DriverState, 15 | } 16 | 17 | impl XAPICDriver { 18 | /// Create a new driver object. 19 | pub fn new(mmio_region: &'static mut [u32]) -> XAPICDriver { 20 | XAPICDriver { 21 | timer_vector: crate::TSC_TIMER_VECTOR, 22 | inner: XAPIC::new(mmio_region), 23 | state: DriverState::Uninitialized, 24 | } 25 | } 26 | } 27 | 28 | impl crate::ApicDriver for XAPICDriver { 29 | /// Is a bootstrap processor? 30 | fn bsp(&self) -> bool { 31 | self.inner.bsp() 32 | } 33 | 34 | /// Return APIC ID. 35 | fn id(&self) -> u32 { 36 | self.inner.id() 37 | } 38 | 39 | /// Return the logical APIC ID. 40 | fn logical_id(&self) -> u32 { 41 | self.inner.logical_id() 42 | } 43 | 44 | /// Read APIC version 45 | fn version(&self) -> u32 { 46 | self.inner.version() 47 | } 48 | 49 | /// End Of Interrupt -- Acknowledge interrupt delivery. 50 | fn eoi(&mut self) { 51 | self.inner.eoi() 52 | } 53 | 54 | /// Enable TSC deadline timer. 55 | fn tsc_enable(&mut self) { 56 | self.inner.tsc_enable(self.timer_vector) 57 | } 58 | 59 | /// Set TSC deadline value. 60 | fn tsc_set(&self, value: u64) { 61 | self.inner.tsc_set(value) 62 | } 63 | 64 | /// Send a INIT IPI to a core. 65 | unsafe fn ipi_init(&mut self, core: ApicId) { 66 | self.inner.ipi_init(core) 67 | } 68 | 69 | /// Deassert INIT IPI. 70 | unsafe fn ipi_init_deassert(&mut self) { 71 | self.inner.ipi_init_deassert() 72 | } 73 | 74 | /// Send a STARTUP IPI to a core. 75 | unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8) { 76 | self.inner.ipi_startup(core, start_page) 77 | } 78 | 79 | /// Send a generic IPI. 80 | unsafe fn send_ipi(&mut self, icr: Icr) { 81 | self.inner.send_ipi(icr) 82 | } 83 | } 84 | 85 | impl DriverControl for XAPICDriver { 86 | /// Attach to the device 87 | fn attach(&mut self) { 88 | self.set_state(DriverState::Attached(0)); 89 | self.inner.attach(); 90 | } 91 | 92 | /// Detach from the device 93 | fn detach(&mut self) { 94 | self.inner.detach(); 95 | self.set_state(DriverState::Detached); 96 | } 97 | 98 | /// Destroy the device. 99 | fn destroy(mut self) { 100 | self.detach(); 101 | self.set_state(DriverState::Destroyed); 102 | } 103 | 104 | /// Query driver state 105 | fn state(&self) -> DriverState { 106 | self.state 107 | } 108 | 109 | /// Set the state of the driver 110 | fn set_state(&mut self, st: DriverState) { 111 | self.state = st; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /lib/bootloader_shared/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bootloader_shared" 3 | version = "0.0.1" 4 | authors = ["Gerd Zellweger "] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [dependencies] 9 | x86 = { version = "0.52", features = ["unstable"] } 10 | arrayvec = { version = "0.7.0", default-features = false } 11 | uefi = "0.15" 12 | -------------------------------------------------------------------------------- /lib/bootloader_shared/README.md: -------------------------------------------------------------------------------- 1 | # bootloader-shared 2 | 3 | Defines the shared/public structure definitions exchanged between the bootloader and the kernel. 4 | -------------------------------------------------------------------------------- /lib/kpi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kpi" 3 | version = "0.1.0" 4 | authors = ["Gerd Zellweger "] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [dependencies] 9 | x86 = { version = "0.52", features = ["unstable"] } 10 | abomonation = { git="https://github.com/hunhoffe/abomonation.git", branch="no-std", default-features = false } 11 | bitflags = "1.2" 12 | core2 = { version = "0.3", default-features = false, features = [ "alloc" ] } 13 | serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } 14 | serde_cbor = { version = "0.11", default-features = false, features = ["alloc"] } 15 | log = "0.4" 16 | static_assertions = "1.1.0" 17 | memoffset = { version = "0.6", features = ["unstable_const"] } 18 | bit_field = "0.10.1" 19 | 20 | [target.'cfg(target_family = "unix")'.dev-dependencies] 21 | env_logger = "*" 22 | -------------------------------------------------------------------------------- /lib/kpi/README.md: -------------------------------------------------------------------------------- 1 | # kpi -- Kernel Public Interface 2 | 3 | Contains system call API, data-structures and definitions that are shared 4 | between user and kernel-space. 5 | -------------------------------------------------------------------------------- /lib/kpi/src/syscalls/system.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! System calls to query for generic system-wide information. 5 | //! (topology, memory, device hardware etc.) 6 | 7 | use alloc::vec::Vec; 8 | 9 | use abomonation::decode; 10 | 11 | use crate::{syscall, *}; 12 | 13 | use crate::system::{CoreId, CpuThread}; 14 | 15 | pub struct System; 16 | 17 | impl System { 18 | /// Query information about available hardware threads. 19 | pub fn threads() -> Result, SystemCallError> { 20 | let mut buf = alloc::vec![0; 5*4096]; 21 | let (r, len) = unsafe { 22 | syscall!( 23 | SystemCall::System as u64, 24 | SystemOperation::GetHardwareThreads as u64, 25 | buf.as_mut_ptr() as u64, 26 | buf.len() as u64, 27 | 2 28 | ) 29 | }; 30 | 31 | if r == 0 { 32 | let len = len as usize; 33 | debug_assert!(len <= buf.len()); 34 | buf.resize(len, 0); 35 | if let Some((deserialized, remaining)) = 36 | unsafe { decode::>(&mut buf[..len]) } 37 | { 38 | if remaining.len() > 0 { 39 | Err(SystemCallError::InternalError) 40 | } else { 41 | // This does perform a copy, which is less than ideal. 42 | Ok(deserialized.to_vec()) 43 | } 44 | } else { 45 | Err(SystemCallError::InternalError) 46 | } 47 | } else { 48 | Err(SystemCallError::from(r)) 49 | } 50 | } 51 | 52 | /// Prints some stats for the core. 53 | pub fn stats() -> Result<(), SystemCallError> { 54 | let r = unsafe { syscall!(SystemCall::System as u64, SystemOperation::Stats as u64, 1) }; 55 | 56 | if r == 0 { 57 | Ok(()) 58 | } else { 59 | Err(SystemCallError::from(r)) 60 | } 61 | } 62 | 63 | /// Get the core id for the current running thread. 64 | pub fn core_id() -> Result { 65 | let (r, id) = unsafe { 66 | syscall!( 67 | SystemCall::System as u64, 68 | SystemOperation::GetCoreID as u64, 69 | 2 70 | ) 71 | }; 72 | 73 | if r == 0 { 74 | Ok(id as usize) 75 | } else { 76 | Err(SystemCallError::from(r)) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/kpi/src/system.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Data structures to exchange system-wide information between kernel and user-space. 5 | use abomonation::{unsafe_abomonate, Abomonation}; 6 | use core2::io::Result as IOResult; 7 | use core2::io::Write; 8 | 9 | /// GlobalThreadId to match atopology::GlobalThreadId 10 | pub type MachineThreadId = usize; 11 | 12 | /// Machine identifier. This is used in rackscale deployments. 13 | /// Defaults to 0 in single-machine deployments. 14 | pub type MachineId = usize; 15 | 16 | /// A system global ID for a CPU hardware thread. 17 | /// High bits are for MachineId, low bits are for MachineThreadId. 18 | pub type GlobalThreadId = usize; 19 | 20 | #[inline(always)] 21 | pub fn new_gtid(mtid: MachineThreadId, mid: MachineId) -> GlobalThreadId { 22 | (mid << (usize::BITS >> 1) as usize) | mtid 23 | } 24 | 25 | #[inline(always)] 26 | pub fn mtid_from_gtid(gtid: GlobalThreadId) -> MachineThreadId { 27 | (gtid << (usize::BITS >> 1) as usize) >> (usize::BITS >> 1) as usize 28 | } 29 | 30 | #[inline(always)] 31 | pub fn mid_from_gtid(gtid: GlobalThreadId) -> MachineId { 32 | gtid >> (usize::BITS >> 1) as usize 33 | } 34 | 35 | /// A hardware scheduling unit (has an APIC), (unique within a core). 36 | pub type ThreadId = usize; 37 | 38 | /// A core, with one or more threads (unique within a packet). 39 | pub type CoreId = usize; 40 | 41 | /// A socket with one or more cores (usually with a shared LLC). 42 | pub type PackageId = usize; 43 | 44 | /// Affinity region, a NUMA node (consists of a bunch of threads/core/packages and memory regions). 45 | pub type NodeId = usize; 46 | 47 | #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone)] 48 | pub struct CpuThread { 49 | /// ID the thread, global within a rackscale system. 50 | pub id: GlobalThreadId, 51 | /// ID of the NUMA node (machine global). 52 | pub node_id: NodeId, 53 | /// ID of the package (machine global). 54 | pub package_id: PackageId, 55 | /// ID of the core (relative to the package). 56 | pub core_id: CoreId, 57 | /// ID of the thread (relative to the core (usually either 0 or 1)). 58 | pub thread_id: ThreadId, 59 | } 60 | unsafe_abomonate!(CpuThread: id, node_id, package_id, core_id, thread_id); 61 | -------------------------------------------------------------------------------- /lib/kpi/src/upcall.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Upcall command passed as the 2nd argument to the upcall. 5 | 6 | pub const NEW_CORE: u64 = 0x99; 7 | -------------------------------------------------------------------------------- /lib/lineup/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | core -------------------------------------------------------------------------------- /lib/lineup/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lineup" 3 | version = "0.0.1" 4 | authors = ["Gerd Zellweger "] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [dependencies] 9 | kpi = { path = "../kpi" } 10 | crossbeam-utils = { version = "0.8", default-features = false } 11 | crossbeam-queue = { version = "0.3", default-features = false, features = ["alloc"] } 12 | either = { version = "1.5", default-features = false } 13 | fringe = { git = "https://github.com/gz/libfringe.git", default-features = false, features = ["alloc"], branch = "new-asm-syntax" } 14 | hashbrown = { version = "0.12.3", features = [ "nightly" ] } 15 | rawtime = "0.0.10" 16 | backtracer_core = "0.0.7" 17 | x86 = { version = "0.52", features = ["unstable"] } 18 | log = "0.4.6" 19 | spin = "0.9" 20 | arr_macro = "0.1" 21 | 22 | [features] 23 | default = [] 24 | latency = [] 25 | 26 | [target.'cfg(target_family = "unix")'.dev-dependencies] 27 | env_logger = "*" 28 | -------------------------------------------------------------------------------- /lib/lineup/README.md: -------------------------------------------------------------------------------- 1 | # lineup 2 | 3 | A light-weight threading library with a cooperative scheduler. 4 | Can be used in `no_std` environments and supports the following features: 5 | 6 | * Mutexes 7 | * Conditional variables 8 | * Reader/Writer locks 9 | * Semaphores 10 | * Thread local storage 11 | * Multicore support (per-core scheduler lists) 12 | 13 | ## Testing 14 | 15 | Run as: `RUST_TEST_THREADS=1 cargo test --release` 16 | 17 | `RUST_TEST_THREADS=1` is technically not necessary but tests are less flaky if 18 | the system has not enough cores. e.g., this can sometimes happen if a test 19 | duration doesn't execute long enough: 20 | 21 | ```log 22 | ---- rwlock::test_rwlock_smp stdout ---- 23 | thread 'main' panicked at 'dropped unfinished Generator', /rustc/2113659479a82ea69633b23ef710b58ab127755e/src/libcore/macros/mod.rs:34:9 24 | note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace 25 | ``` 26 | 27 | The `scheduler_is_parallel` test also checks timing and can be flaky. 28 | -------------------------------------------------------------------------------- /lib/lineup/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! A user-space thread scheduler with support for synchronization primitives. 5 | 6 | #![feature(drain_filter)] 7 | #![feature(linkage)] 8 | #![feature(thread_local)] 9 | #![feature(test)] 10 | #![feature(asm_const)] 11 | #![cfg_attr(test, feature(bench_black_box))] 12 | #![cfg_attr(not(test), no_std)] 13 | 14 | extern crate alloc; 15 | 16 | pub mod condvar; 17 | pub mod mutex; 18 | pub mod rwlock; 19 | pub mod scheduler; 20 | pub mod semaphore; 21 | pub mod stack; 22 | pub mod threads; 23 | pub mod tls2; 24 | pub mod upcalls; 25 | 26 | /// Type to represent a core id for the scheduler. 27 | type CoreId = usize; 28 | 29 | /// A utility function that converts a core_id (which may not be sequential) 30 | /// to a form more easily used for indexing 31 | #[inline(always)] 32 | pub fn core_id_to_index(core_id: CoreId) -> usize { 33 | let machine_id = kpi::system::mid_from_gtid(core_id); 34 | if machine_id == 0 { 35 | // This is controller (should never happen) or non-rackscale 36 | core_id 37 | } else { 38 | // The controller (which will never need this) is always machine_id 0, so 39 | // decrement here for rackscale clients. 40 | kpi::process::MAX_CORES_PER_MACHINE * (machine_id - 1) 41 | + kpi::system::mtid_from_gtid(core_id) 42 | } 43 | } 44 | 45 | /// Type to represent an IRQ vector. 46 | type IrqVector = u64; 47 | -------------------------------------------------------------------------------- /lib/lineup/src/semaphore.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use core::cell::UnsafeCell; 5 | 6 | use crate::condvar::CondVar; 7 | use crate::mutex::Mutex; 8 | 9 | #[derive(Debug)] 10 | pub struct Semaphore { 11 | inner: UnsafeCell, 12 | } 13 | 14 | unsafe impl Send for Semaphore {} 15 | unsafe impl Sync for Semaphore {} 16 | 17 | impl Semaphore { 18 | pub fn new(count: isize) -> Semaphore { 19 | Semaphore { 20 | inner: UnsafeCell::new(SemaphoreInner::new(count)), 21 | } 22 | } 23 | 24 | pub fn up(&self) { 25 | let sem = unsafe { &mut *self.inner.get() }; 26 | sem.up() 27 | } 28 | 29 | pub fn down(&self) { 30 | let sem = unsafe { &mut *self.inner.get() }; 31 | sem.down() 32 | } 33 | } 34 | 35 | #[derive(Debug)] 36 | struct SemaphoreInner { 37 | count: isize, 38 | mutex: Mutex, 39 | cv: CondVar, 40 | } 41 | 42 | impl Drop for SemaphoreInner { 43 | fn drop(&mut self) {} 44 | } 45 | 46 | impl SemaphoreInner { 47 | pub fn new(count: isize) -> SemaphoreInner { 48 | SemaphoreInner { 49 | count, 50 | mutex: Mutex::new_kmutex(), 51 | cv: CondVar::new(), 52 | } 53 | } 54 | 55 | pub fn up(&mut self) { 56 | self.mutex.enter(); 57 | self.count += 1; 58 | if self.count > 0 { 59 | self.cv.signal(); 60 | } 61 | self.mutex.exit(); 62 | } 63 | 64 | pub fn down(&mut self) { 65 | self.mutex.enter(); 66 | if self.count <= 0 { 67 | self.cv.wait(&self.mutex) 68 | } 69 | self.count -= self.count; 70 | self.mutex.exit(); 71 | } 72 | } 73 | 74 | #[test] 75 | fn test_semaphore() { 76 | use alloc::sync::Arc; 77 | use core::ptr; 78 | 79 | use crate::scheduler::SmpScheduler; 80 | use crate::stack::DEFAULT_STACK_SIZE_BYTES; 81 | use crate::tls2::SchedulerControlBlock; 82 | 83 | let s: SmpScheduler = Default::default(); 84 | 85 | let cv = Arc::new(Semaphore::new(0)); 86 | let cv1: Arc = cv.clone(); 87 | let cv2: Arc = cv.clone(); 88 | 89 | s.spawn( 90 | DEFAULT_STACK_SIZE_BYTES, 91 | move |_yielder| { 92 | for _i in 0..5 { 93 | cv2.down(); 94 | } 95 | }, 96 | ptr::null_mut(), 97 | 0, 98 | None, 99 | ); 100 | 101 | s.spawn( 102 | DEFAULT_STACK_SIZE_BYTES, 103 | move |_yielder| { 104 | for _i in 0..5 { 105 | cv1.up(); 106 | } 107 | }, 108 | ptr::null_mut(), 109 | 0, 110 | None, 111 | ); 112 | 113 | let scb: SchedulerControlBlock = SchedulerControlBlock::new(0); 114 | s.run(&scb); 115 | } 116 | -------------------------------------------------------------------------------- /lib/lineup/src/stack.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use alloc::alloc::{alloc, dealloc}; 5 | use core::alloc::Layout; 6 | 7 | use fringe::Stack; 8 | 9 | /// Default stack size in bytes. 10 | pub const DEFAULT_STACK_SIZE_BYTES: usize = 32 * 4096; 11 | 12 | /// LineupStack holds a non-guarded, heap-allocated stack. 13 | #[derive(Debug, PartialEq)] 14 | pub struct LineupStack { 15 | base_ptr: *mut u8, 16 | layout: Layout, 17 | dealloc: bool, 18 | } 19 | 20 | impl Default for LineupStack { 21 | fn default() -> Self { 22 | LineupStack::from_size(DEFAULT_STACK_SIZE_BYTES) 23 | } 24 | } 25 | 26 | impl LineupStack { 27 | /// Allocates a new stack with `size` accessible bytes and alignment appropriate 28 | /// for the current platform using the default Rust allocator. 29 | pub fn from_size(size: usize) -> LineupStack { 30 | unsafe { 31 | let aligned_size = size & !(fringe::STACK_ALIGNMENT - 1); 32 | let layout = Layout::from_size_align_unchecked(aligned_size, fringe::STACK_ALIGNMENT); 33 | 34 | let base_ptr = alloc(layout); 35 | assert!(!base_ptr.is_null()); 36 | 37 | LineupStack { 38 | base_ptr, 39 | layout, 40 | dealloc: true, 41 | } 42 | } 43 | } 44 | 45 | pub fn from_ptr(base_ptr: *mut u8, size: usize, dealloc: bool) -> LineupStack { 46 | unsafe { 47 | let aligned_size = size & !(fringe::STACK_ALIGNMENT - 1); 48 | assert!(aligned_size == size, "Provided size is aligned"); 49 | let layout = Layout::from_size_align_unchecked(aligned_size, fringe::STACK_ALIGNMENT); 50 | 51 | LineupStack { 52 | base_ptr, 53 | layout, 54 | dealloc, 55 | } 56 | } 57 | } 58 | } 59 | 60 | impl Drop for LineupStack { 61 | fn drop(&mut self) { 62 | if self.dealloc { 63 | unsafe { dealloc(self.base_ptr, self.layout) } 64 | } 65 | } 66 | } 67 | 68 | unsafe impl Stack for LineupStack { 69 | #[inline(always)] 70 | fn base(&self) -> *mut u8 { 71 | // The slice cannot wrap around the address space, so the conversion from usize 72 | // to isize will not wrap either. 73 | let len = self.layout.size() as isize; 74 | unsafe { self.limit().offset(len) } 75 | } 76 | 77 | #[inline(always)] 78 | fn limit(&self) -> *mut u8 { 79 | self.base_ptr 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/lineup/src/tls2/nrk.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use core::alloc::Layout; 5 | 6 | use x86::bits64::segmentation; 7 | 8 | use super::{SchedulerControlBlock, ThreadControlBlock}; 9 | 10 | pub(crate) unsafe fn get_tcb<'a>() -> *mut ThreadControlBlock<'a> { 11 | segmentation::rdfsbase() as *mut ThreadControlBlock 12 | } 13 | 14 | pub(crate) unsafe fn set_tcb(t: *mut ThreadControlBlock) { 15 | segmentation::wrfsbase(t as u64) 16 | } 17 | 18 | pub(crate) unsafe fn get_scb() -> *const SchedulerControlBlock { 19 | segmentation::rdgsbase() as *const SchedulerControlBlock 20 | } 21 | 22 | pub(crate) unsafe fn set_scb(scb: *const SchedulerControlBlock) { 23 | segmentation::wrgsbase(scb as *const _ as u64) 24 | } 25 | 26 | /// Determines the necessary space for per-thread TLS memory region. 27 | /// 28 | /// Total required bytes is the sum of the `tdata`, `tbss`, 29 | /// and a statically defined extra section. 30 | /// (i.e., the sum of all return values) 31 | pub fn get_tls_info() -> (&'static [u8], Layout) { 32 | let pinfo: kpi::process::ProcessInfo = 33 | kpi::syscalls::Process::process_info().expect("Can't get pinfo?"); 34 | if pinfo.has_tls { 35 | let _bss_size = pinfo.tls_len_total - pinfo.tls_data_len; 36 | unsafe { 37 | // Safe: We know this exists because our ELF loader put TLS there (hopefully) 38 | ( 39 | core::slice::from_raw_parts( 40 | pinfo.tls_data as *const u8, 41 | pinfo.tls_data_len as usize, 42 | ), 43 | Layout::from_size_align_unchecked( 44 | pinfo.tls_len_total as usize + core::mem::size_of::(), 45 | pinfo.alignment as usize, 46 | ), 47 | ) 48 | } 49 | } else { 50 | (&[], Layout::new::()) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/lineup/src/tls2/unix.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! A silly implementation of get/set tcb/scb on unix 5 | //! 6 | //! Super meta since we use posix/thread_local to 7 | //! implement it. 8 | use core::alloc::Layout; 9 | use core::cell::Cell; 10 | use core::{mem, ptr}; 11 | 12 | use super::{SchedulerControlBlock, ThreadControlBlock}; 13 | 14 | #[thread_local] 15 | pub static TCB: Cell<*mut ThreadControlBlock> = Cell::new(ptr::null_mut()); 16 | 17 | #[thread_local] 18 | pub static SCB: Cell<*const SchedulerControlBlock> = Cell::new(ptr::null()); 19 | 20 | pub(crate) unsafe fn get_tcb<'a>() -> *mut ThreadControlBlock<'a> { 21 | mem::transmute::<*mut ThreadControlBlock<'static>, *mut ThreadControlBlock<'a>>(TCB.get()) 22 | } 23 | 24 | pub(crate) unsafe fn set_tcb<'a>(tcb: *mut ThreadControlBlock<'a>) { 25 | TCB.set(mem::transmute::< 26 | *mut ThreadControlBlock<'a>, 27 | *mut ThreadControlBlock<'static>, 28 | >(tcb)); 29 | } 30 | 31 | pub(crate) unsafe fn get_scb() -> *const SchedulerControlBlock { 32 | SCB.get() 33 | } 34 | 35 | pub(crate) unsafe fn set_scb(scb: *const SchedulerControlBlock) { 36 | SCB.set(scb); 37 | } 38 | 39 | /// A poor way to estimate the TLS size on unix. 40 | #[cfg(target_family = "unix")] 41 | pub fn get_tls_info() -> (&'static [u8], Layout) { 42 | // We only use this for tests, so we just estimate our TLS size... 43 | // Ideally we parse the ELF of our process to determine the static TLS size 44 | (&[], Layout::new::()) 45 | } 46 | -------------------------------------------------------------------------------- /lib/lineup/src/upcalls.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! A mechanism for upcalls that the scheduler uses to notify 5 | //! an application about events: a thread is blocking etc. 6 | //! 7 | //! In the current form, simply modelled to support rump upcalls. 8 | //! Should be generalized in the future. 9 | 10 | use crate::mutex; 11 | use core::fmt; 12 | 13 | /// Notification up-calls from the scheduler to the application 14 | /// (here to support the rump runtime). 15 | #[derive(Clone, Copy)] 16 | pub struct Upcalls { 17 | pub curlwp: fn() -> u64, 18 | pub schedule: fn(&i32, Option<&mutex::Mutex>), 19 | pub deschedule: fn(&mut i32, Option<&mutex::Mutex>), 20 | pub context_switch: fn(*mut u8, *mut u8), 21 | } 22 | 23 | impl Default for Upcalls { 24 | fn default() -> Self { 25 | Upcalls { 26 | curlwp: noop_curlwp, 27 | schedule: noop_schedule, 28 | deschedule: noop_unschedule, 29 | context_switch: noop_context_switch, 30 | } 31 | } 32 | } 33 | 34 | impl fmt::Debug for Upcalls { 35 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 36 | write!(f, "Upcalls {{}}") 37 | } 38 | } 39 | 40 | /// Dummy implementation of noop_context_switch(). 41 | fn noop_context_switch(_a1: *mut u8, _a2: *mut u8) {} 42 | 43 | /// Dummy implementation of noop_curlwp(). 44 | fn noop_curlwp() -> u64 { 45 | 0 46 | } 47 | 48 | /// Dummy implementation of unschedule(). 49 | fn noop_unschedule(_nlocks: &mut i32, _mtx: Option<&mutex::Mutex>) {} 50 | 51 | /// Dummy implementation of schedule(). 52 | fn noop_schedule(_nlocks: &i32, _mtx: Option<&mutex::Mutex>) {} 53 | -------------------------------------------------------------------------------- /lib/rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rpc" 3 | version = "0.1.0" 4 | authors = ["Erika Hunhoff "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | abomonation = { git="https://github.com/hunhoffe/abomonation.git", branch="no-std", default-features = false } 11 | core2 = { version = "0.3", default-features = false, features = [ "alloc" ] } 12 | hashbrown = { version = "0.11", features = [ "nightly" ] } 13 | lazy_static = { version = "1.4", features = ["spin_no_std"] } 14 | log = "0.4" 15 | rawtime = "0.0.10" 16 | spin = "0.9.1" 17 | smoltcp = { version = "0.8.0", default-features = false, features = [ "alloc", "log", "proto-ipv4", "socket-tcp", "medium-ethernet" ] } 18 | vmxnet3 = { path = "../vmxnet3" } 19 | 20 | [features] 21 | std = [] 22 | -------------------------------------------------------------------------------- /lib/rpc/src/client.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use alloc::boxed::Box; 5 | 6 | use crate::rpc::*; 7 | use crate::transport::Transport; 8 | 9 | pub struct Client { 10 | transport: Box, 11 | hdr: RPCHeader, 12 | } 13 | 14 | impl Client { 15 | pub fn new(transport: Box) -> Client { 16 | Client { 17 | transport, 18 | hdr: RPCHeader::default(), 19 | } 20 | } 21 | 22 | /// Registers with a RPC server 23 | pub fn connect(&mut self, data_in: &[&[u8]]) -> Result<(), RPCError> { 24 | self.transport.client_connect()?; 25 | self.call(RPC_TYPE_CONNECT, data_in, &mut []) 26 | } 27 | 28 | /// Calls a remote RPC function with ID 29 | pub fn call( 30 | &mut self, 31 | rpc_id: RPCType, 32 | data_in: &[&[u8]], 33 | data_out: &mut [&mut [u8]], 34 | ) -> Result<(), RPCError> { 35 | // Calculate total data_out len 36 | let data_in_len = data_in.iter().fold(0, |acc, x| acc + x.len()); 37 | debug_assert!(data_in_len < MsgLen::MAX as usize); 38 | 39 | // Create request header and send message. It is safe to create a mutable reference here 40 | // because it is assumed there will only be one invocation of call() running at a time, and only 41 | // the client has access to this field. 42 | let mut hdr = &mut self.hdr; 43 | hdr.msg_type = rpc_id; 44 | hdr.msg_len = data_in_len as MsgLen; 45 | self.transport.send_msg(hdr, data_in)?; 46 | 47 | // Receive the response 48 | self.transport.recv_msg(hdr, data_out)?; 49 | Ok(()) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | #![cfg_attr(not(any(test, feature = "std")), no_std)] 5 | #![feature(allocator_api)] 6 | 7 | #[cfg(any(test, feature = "std"))] 8 | extern crate std; 9 | 10 | extern crate abomonation; 11 | extern crate alloc; 12 | extern crate core2; 13 | extern crate smoltcp; 14 | extern crate vmxnet3; 15 | 16 | pub mod client; 17 | pub mod rpc; 18 | pub mod server; 19 | pub mod transport; 20 | -------------------------------------------------------------------------------- /lib/rpc/src/rpc.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 University of Colorado. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use abomonation::{unsafe_abomonate, Abomonation}; 5 | use core::convert::TryInto; 6 | 7 | #[derive(Debug, Eq, PartialEq, PartialOrd, Clone, Copy)] 8 | pub enum RPCError { 9 | // RPC 10 | MissingData, 11 | ExtraData, 12 | TransportError, 13 | MalformedResponse, 14 | MalformedRequest, 15 | InternalError, 16 | DuplicateRPCType, 17 | NoHandlerForRPCType, 18 | ClientInitializationError, 19 | ClientConnectError, 20 | ServerListenError, 21 | MemoryAllocationError, 22 | RegistrationError, 23 | } 24 | unsafe_abomonate!(RPCError); 25 | 26 | pub type RPCType = u8; 27 | pub const RPC_TYPE_CONNECT: u8 = 0u8; 28 | pub type MsgId = u8; 29 | pub type MsgLen = u16; 30 | 31 | #[derive(Debug, Default, Copy, Clone)] 32 | #[repr(C, packed)] 33 | pub struct RPCHeader { 34 | pub msg_id: MsgId, 35 | pub msg_type: RPCType, 36 | pub msg_len: MsgLen, 37 | } 38 | pub const HDR_LEN: usize = core::mem::size_of::(); 39 | 40 | impl RPCHeader { 41 | /// # Safety 42 | /// - `self` must be valid RPCHeader 43 | #[inline(always)] 44 | pub unsafe fn as_mut_bytes(&mut self) -> &mut [u8; HDR_LEN] { 45 | ::core::slice::from_raw_parts_mut((self as *const RPCHeader) as *mut u8, HDR_LEN) 46 | .try_into() 47 | .expect("slice with incorrect length") 48 | } 49 | 50 | /// # Safety 51 | /// - `self` must be valid RPCHeader 52 | #[inline(always)] 53 | pub unsafe fn as_bytes(&self) -> &[u8; HDR_LEN] { 54 | ::core::slice::from_raw_parts((self as *const RPCHeader) as *const u8, HDR_LEN) 55 | .try_into() 56 | .expect("slice with incorrect length") 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/rpc/src/transport/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod shmem; 2 | mod smoltcp; 3 | 4 | pub use self::smoltcp::TCPTransport; 5 | pub use shmem::transport::ShmemTransport; 6 | 7 | use crate::rpc::{RPCError, RPCHeader}; 8 | 9 | pub trait Transport { 10 | fn max_send(&self) -> usize; 11 | 12 | fn max_recv(&self) -> usize; 13 | 14 | /// Receive an RPC message from a remote node, blocking 15 | fn recv_msg(&self, hdr: &mut RPCHeader, payload: &mut [&mut [u8]]) -> Result<(), RPCError>; 16 | 17 | /// Receive an RPC message from a remote node, non-blocking except to avoid partial receive 18 | fn try_recv_msg( 19 | &self, 20 | hdr: &mut RPCHeader, 21 | payload: &mut [&mut [u8]], 22 | ) -> Result; 23 | 24 | /// Send an RPC message to a remote node, blocking 25 | fn send_msg(&self, hdr: &RPCHeader, payload: &[&[u8]]) -> Result<(), RPCError>; 26 | 27 | /// Send an RPC message to a remote node, non-blocking except to avoid partial send 28 | fn try_send_msg(&self, hdr: &RPCHeader, payload: &[&[u8]]) -> Result; 29 | 30 | /// Controller-side implementation for LITE join_cluster() 31 | fn client_connect(&mut self) -> Result<(), RPCError>; 32 | 33 | /// Client-side implementation for LITE join_cluster() 34 | fn server_accept(&self) -> Result<(), RPCError>; 35 | } 36 | -------------------------------------------------------------------------------- /lib/rpc/src/transport/shmem/allocator.rs: -------------------------------------------------------------------------------- 1 | use alloc::alloc::handle_alloc_error; 2 | use core::alloc::Layout; 3 | use core::alloc::{AllocError, Allocator}; 4 | use core::ptr::NonNull; 5 | use core::slice::from_raw_parts_mut; 6 | use core::sync::atomic::{AtomicU64, Ordering}; 7 | 8 | pub struct ShmemAllocator { 9 | base: u64, 10 | size: u64, 11 | next: AtomicU64, 12 | } 13 | 14 | impl ShmemAllocator { 15 | pub fn new(base: u64, size: u64) -> ShmemAllocator { 16 | ShmemAllocator { 17 | base, 18 | size, 19 | next: AtomicU64::new(base), 20 | } 21 | } 22 | 23 | fn try_alloc(&self, cur_next: u64, size: usize) -> bool { 24 | if cur_next + size as u64 > self.base + self.size { 25 | return false; 26 | } 27 | 28 | self.next 29 | .compare_exchange_weak( 30 | cur_next, 31 | cur_next + size as u64, 32 | Ordering::Relaxed, 33 | Ordering::Relaxed, 34 | ) 35 | .is_ok() 36 | } 37 | } 38 | 39 | unsafe impl Allocator for ShmemAllocator { 40 | fn allocate(&self, layout: Layout) -> Result, AllocError> { 41 | let ptr = self.next.load(Ordering::Relaxed); 42 | match self.try_alloc(ptr, layout.size()) { 43 | true => unsafe { 44 | Ok(NonNull::new_unchecked(from_raw_parts_mut( 45 | (ptr) as *mut u8, 46 | layout.size(), 47 | ))) 48 | }, 49 | false => handle_alloc_error(layout), 50 | } 51 | } 52 | 53 | unsafe fn deallocate(&self, ptr: NonNull, _layout: Layout) { 54 | log::debug!("deallocate: {:?}", ptr); 55 | } 56 | } 57 | 58 | #[cfg(test)] 59 | mod test { 60 | use super::*; 61 | 62 | #[test] 63 | fn test_allocator() { 64 | let base = 0x1000; 65 | let size = 0x2000; 66 | let allocator = ShmemAllocator::new(base, size); 67 | let layout = Layout::from_size_align(0x1000, 1).unwrap(); 68 | let ptr = allocator.allocate(layout).unwrap(); 69 | assert_eq!((ptr.cast().as_ptr() as *const u8) as u64, base); 70 | assert_eq!(allocator.next.load(Ordering::Relaxed), base + 0x1000); 71 | } 72 | 73 | #[test] 74 | fn test_allocator_overflow() { 75 | let base = 0x1000; 76 | let size = 0x2000; 77 | let allocator = ShmemAllocator::new(base, size); 78 | let layout = Layout::from_size_align(0x1000, 1).unwrap(); 79 | let ptr = allocator.allocate(layout).unwrap(); 80 | assert_eq!((ptr.cast().as_ptr() as *const u8) as u64, base); 81 | assert_eq!(allocator.next.load(Ordering::Relaxed), base + 0x1000); 82 | let ptr = allocator.allocate(layout).unwrap(); 83 | assert_eq!((ptr.cast().as_ptr() as *const u8) as u64, base + 0x1000); 84 | assert_eq!(allocator.next.load(Ordering::Relaxed), base + 0x2000); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/rpc/src/transport/shmem/mod.rs: -------------------------------------------------------------------------------- 1 | // Shmem Transport 2 | use alloc::alloc::Allocator; 3 | 4 | use alloc::sync::Arc; 5 | pub mod allocator; 6 | pub mod transport; 7 | 8 | pub mod queue_mpmc; 9 | pub use queue_mpmc::{Queue, QueueError}; 10 | 11 | #[repr(transparent)] 12 | pub struct Sender<'a>(Arc>); 13 | 14 | unsafe impl<'a> Send for Sender<'a> {} 15 | unsafe impl<'a> Sync for Sender<'a> {} 16 | 17 | impl<'a> Sender<'a> { 18 | pub fn with_capacity_in(capacity: usize, alloc: A) -> Sender<'a> { 19 | Sender(Arc::new( 20 | Queue::with_capacity_in(false, capacity, alloc).unwrap(), 21 | )) 22 | } 23 | 24 | #[inline(always)] 25 | pub fn with_shared_queue(q: Arc>) -> Sender<'a> { 26 | Sender(q.clone()) 27 | } 28 | 29 | #[inline(always)] 30 | pub fn send(&self, data: &[&[u8]]) -> bool { 31 | while !self.0.enqueue(data) {} 32 | true 33 | } 34 | 35 | #[inline(always)] 36 | pub fn try_send(&self, data: &[&[u8]]) -> bool { 37 | self.0.enqueue(data) 38 | } 39 | } 40 | 41 | #[repr(transparent)] 42 | pub struct Receiver<'a>(Arc>); 43 | 44 | unsafe impl<'a> Send for Receiver<'a> {} 45 | unsafe impl<'a> Sync for Receiver<'a> {} 46 | 47 | impl<'a> Receiver<'a> { 48 | pub fn with_capacity_in(capacity: usize, alloc: A) -> Receiver<'a> { 49 | Receiver(Arc::new( 50 | Queue::with_capacity_in(true, capacity, alloc).unwrap(), 51 | )) 52 | } 53 | 54 | #[inline(always)] 55 | pub fn with_shared_queue(q: Arc>) -> Receiver<'a> { 56 | Receiver(q.clone()) 57 | } 58 | 59 | #[inline(always)] 60 | pub fn recv(&self, data_out: &mut [&mut [u8]]) -> usize { 61 | loop { 62 | let ret = self.0.dequeue(data_out); 63 | if let Ok(bytes_received) = ret { 64 | return bytes_received; 65 | } 66 | } 67 | } 68 | 69 | #[inline(always)] 70 | pub fn try_recv(&self, data_out: &mut [&mut [u8]]) -> Result { 71 | self.0.dequeue(data_out) 72 | } 73 | } 74 | 75 | #[cfg(test)] 76 | mod tests { 77 | #[test] 78 | fn shared_queue_tests() { 79 | use super::*; 80 | 81 | let queue = Arc::new(Queue::new().unwrap()); 82 | let sender = Sender::with_shared_queue(queue.clone()); 83 | let receiver = Receiver::with_shared_queue(queue.clone()); 84 | 85 | let send_data: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 86 | sender.send(&[&send_data]); 87 | 88 | let mut rx_data = [0u8; 10]; 89 | assert_eq!(receiver.recv(&mut [&mut rx_data]), 10); 90 | assert_eq!(&send_data, &rx_data[0..send_data.len()]); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/vibrio/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vibrio" 3 | version = "0.1.0" 4 | authors = ["Gerd Zellweger "] 5 | edition = "2018" 6 | description = "A small user-space runtime that interacts with the nrk kernel." 7 | build = "build.rs" 8 | license = "MIT OR Apache-2.0" 9 | 10 | [lib] 11 | name = "vibrio" 12 | crate-type = ["staticlib", "rlib"] 13 | 14 | [dependencies] 15 | kpi = { path = "../kpi" } 16 | lineup = { path = "../lineup" } 17 | bitflags = "1.2" 18 | log = "0.4" 19 | x86 = { version = "0.52", features = ["unstable"] } 20 | slabmalloc = "0.10" 21 | rawtime = "0.0.10" 22 | spin = "0.9.2" 23 | cstr_core = { version = "0.2.3", default-features = false , features = ["alloc"] } 24 | hashbrown = { version = "0.11.2", optional = true } 25 | lazy_static = { version = "1.3", features = ["spin_no_std"] } 26 | serde_cbor = { version = "0.11", default-features = false, features = ["alloc"] } 27 | crossbeam-utils = {version = "0.8", default-features = false} 28 | arrayvec = { version = "0.7.0", default-features = false } 29 | 30 | [target.'cfg(target_os = "nrk")'.dependencies] 31 | rumpkernel = { version = "0.0.5", optional = true } 32 | 33 | 34 | [features] 35 | default = [] 36 | # Include rumpkernel runtime 37 | rumprt = ["rumpkernel", "hashbrown"] 38 | # Use virtio for default networking driver 39 | virtio = [] 40 | -------------------------------------------------------------------------------- /lib/vibrio/README.md: -------------------------------------------------------------------------------- 1 | # virbio 2 | 3 | A user-space runtime library with the following features: 4 | 5 | * kernel interface (kpi) 6 | * memory manager 7 | * green-threads scheduler 8 | * rumpkernel integration (feature flag) 9 | -------------------------------------------------------------------------------- /lib/vibrio/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | fn main() { 5 | #[cfg(all(target_os = "nrk", feature = "rumprt"))] 6 | rumprt_includes(); 7 | } 8 | 9 | #[allow(unused)] 10 | fn rumprt_includes() { 11 | let libs = [ 12 | "rump", 13 | "rumpvfs", 14 | "rumpdev", 15 | "rumpfs_tmpfs", 16 | "rumpnet_config", 17 | "rumpnet", 18 | "rumpdev_bpf", 19 | "rumpdev_vnd", 20 | "rumpdev_rnd", 21 | "rumpnet_netinet", 22 | "rumpnet_net", 23 | "rumpnet_netinet6", 24 | "rumpnet_local", 25 | "rumpfs_ffs", 26 | "rumpfs_cd9660", 27 | "rumpfs_ext2fs", 28 | "rumpdev_disk", 29 | "rumpdev_virtio_if_vioif", 30 | "rumpdev_virtio_ld", 31 | "rumpdev_virtio_viornd", 32 | "rumpdev_pci_virtio", 33 | "rumpdev_pci", 34 | "rumpdev_virtio_vioscsi", 35 | "rumpdev_scsipi", 36 | "rumpdev_audio", 37 | "rumpdev_audio_ac97", 38 | "rumpdev_pci_auich", 39 | "rumpdev_pci_eap", 40 | "rumpdev_pci_hdaudio", 41 | "rumpdev_hdaudio_hdafg", 42 | "rumpdev_pci_if_wm", 43 | "rumpdev_miiphy", 44 | "rumpdev_pci_usbhc", 45 | "rumpdev_usb", 46 | "rumpdev_umass", 47 | "rumpkern_mman", 48 | ]; 49 | 50 | for lib in libs { 51 | println!("cargo:rustc-link-lib=static={}", lib); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/vibrio/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! vibrio is the user-space library that interacts with the kernel. 5 | //! 6 | //! It also incorporates and exports the [kpi] crate which defines the interface between 7 | //! the kernel and user-space (clients should only have to rely on this crate). 8 | #![no_std] 9 | #![feature( 10 | asm_const, 11 | alloc_error_handler, 12 | panic_info_message, 13 | c_variadic, 14 | ptr_internals, 15 | lang_items, 16 | thread_local 17 | )] 18 | extern crate alloc; 19 | extern crate kpi; 20 | #[cfg(not(target_os = "nrk"))] 21 | extern crate std; 22 | 23 | pub use kpi::*; 24 | 25 | extern crate arrayvec; 26 | extern crate lazy_static; 27 | 28 | pub mod mem; 29 | #[cfg(target_os = "nrk")] 30 | pub mod upcalls; 31 | pub mod vconsole; 32 | pub mod writer; 33 | 34 | #[cfg(feature = "rumprt")] 35 | pub mod rumprt; 36 | 37 | #[cfg(target_os = "nrk")] 38 | #[panic_handler] 39 | fn panic(info: &core::panic::PanicInfo) -> ! { 40 | sys_println!("System panic encountered"); 41 | if let Some(message) = info.message() { 42 | sys_print!(": '{}'", message); 43 | } 44 | if let Some(location) = info.location() { 45 | sys_println!(" in {}:{}", location.file(), location.line()); 46 | } else { 47 | sys_println!(""); 48 | } 49 | 50 | unsafe { 51 | let rsp = x86::bits64::registers::rsp(); 52 | for i in 0..32 { 53 | let ptr = (rsp as *const u64).offset(i); 54 | sys_println!("stack[{}] = {:#x}", i, *ptr); 55 | } 56 | } 57 | 58 | crate::syscalls::Process::exit(99) 59 | } 60 | 61 | #[cfg(target_os = "nrk")] 62 | #[no_mangle] 63 | pub unsafe extern "C" fn _Unwind_Resume() { 64 | unreachable!("_Unwind_Resume"); 65 | } 66 | 67 | #[cfg(target_os = "nrk")] 68 | #[lang = "eh_personality"] 69 | pub extern "C" fn eh_personality() {} 70 | 71 | #[cfg(target_os = "nrk")] 72 | #[alloc_error_handler] 73 | fn oom(layout: core::alloc::Layout) -> ! { 74 | panic!("oom {:?}", layout) 75 | } 76 | -------------------------------------------------------------------------------- /lib/vibrio/src/rumprt/crt/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Runtime support for error handling (i.e., retrieve errno). 5 | 6 | use crate::rumprt::c_int; 7 | use lineup::tls2::Environment; 8 | 9 | /// Retrieves a mutable pointer to set the current _errno. 10 | /// 11 | /// # TODO 12 | /// This should probably be thread safe? 13 | #[no_mangle] 14 | pub unsafe extern "C" fn __errno() -> *mut c_int { 15 | &mut Environment::thread().errno as *mut c_int 16 | } 17 | -------------------------------------------------------------------------------- /lib/vibrio/src/rumprt/crt/message_queue.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Message queue implementation. 5 | 6 | #[no_mangle] 7 | pub unsafe extern "C" fn _sys_mq_receive() { 8 | unreachable!("_sys_mq_receive"); 9 | } 10 | 11 | #[no_mangle] 12 | pub unsafe extern "C" fn _sys_mq_send() { 13 | unreachable!("_sys_mq_send"); 14 | } 15 | 16 | #[no_mangle] 17 | pub unsafe extern "C" fn _sys___mq_timedreceive50() { 18 | unreachable!("_sys___mq_timedreceive50"); 19 | } 20 | 21 | #[no_mangle] 22 | pub unsafe extern "C" fn _sys___mq_timedsend50() { 23 | unreachable!("_sys___mq_timedsend50"); 24 | } 25 | 26 | #[no_mangle] 27 | pub unsafe extern "C" fn _sys_msgrcv() { 28 | unreachable!("_sys_msgrcv"); 29 | } 30 | 31 | #[no_mangle] 32 | pub unsafe extern "C" fn _sys_msgsnd() { 33 | unreachable!("_sys_msgsnd"); 34 | } 35 | -------------------------------------------------------------------------------- /lib/vibrio/src/rumprt/crt/process.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Functions to interact/modify process state 5 | 6 | use log::{error, info}; 7 | 8 | use crate::rumprt::{c_int, c_void, pid_t}; 9 | 10 | /// The execve() system call transforms the calling process into a new 11 | /// process. The new process is constructed from an ordinary file, whose 12 | /// name is pointed to by path, called the new process file. 13 | #[no_mangle] 14 | pub unsafe extern "C" fn execve() { 15 | unreachable!("execve"); 16 | } 17 | 18 | /// Exits the current program. 19 | #[no_mangle] 20 | pub unsafe extern "C" fn _exit(exit_val: c_int) { 21 | extern "C" { 22 | fn pthread_exit(ptr: *mut c_void); 23 | } 24 | if exit_val > 0 { 25 | error!("===> Program error, exit with {}", exit_val); 26 | } else { 27 | info!("===> Program exited successfully"); 28 | } 29 | 30 | pthread_exit(exit_val as *mut c_void); 31 | } 32 | 33 | /// Forks the process. 34 | #[no_mangle] 35 | pub unsafe extern "C" fn __fork() -> c_int { 36 | info!("__fork called, not supported"); 37 | crate::rumprt::errno::ENOTSUP 38 | } 39 | 40 | #[no_mangle] 41 | pub unsafe extern "C" fn __vfork14() -> c_int { 42 | error!("__vfork14 called, not supported"); 43 | crate::rumprt::errno::ENOTSUP 44 | } 45 | 46 | /// Returns information describing the resources used by the current process, 47 | /// or all its terminated child processes. 48 | #[no_mangle] 49 | pub unsafe extern "C" fn __getrusage50() { 50 | unreachable!("__getrusage50"); 51 | } 52 | 53 | /// The kill function sends the signal given by sig to pid, 54 | /// a process or a group of processes. 55 | #[no_mangle] 56 | pub unsafe extern "C" fn kill(pid: pid_t, signal: c_int) { 57 | unreachable!("kill pid: {} -> sig:{}", pid, signal); 58 | } 59 | -------------------------------------------------------------------------------- /lib/vibrio/src/rumprt/crt/scheduler.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Implements the interactions with the scheduler. 5 | //! 6 | //! Just stubs that don't to anything for now. 7 | 8 | use crate::rumprt::{c_int, c_size_t, c_void, errno}; 9 | 10 | #[no_mangle] 11 | pub unsafe extern "C" fn _sys_sched_yield() { 12 | unreachable!("_sys_sched_yield"); 13 | } 14 | 15 | #[no_mangle] 16 | pub unsafe extern "C" fn _sched_getaffinity() { 17 | unreachable!("_sched_getaffinity"); 18 | } 19 | 20 | #[no_mangle] 21 | pub unsafe extern "C" fn _sched_getparam() { 22 | unreachable!("_sched_getparam"); 23 | } 24 | 25 | #[no_mangle] 26 | pub unsafe extern "C" fn _sched_protect() -> c_int { 27 | return 0; 28 | } 29 | 30 | #[no_mangle] 31 | pub unsafe extern "C" fn _sched_setaffinity() { 32 | unreachable!("_sched_setaffinity"); 33 | } 34 | 35 | #[no_mangle] 36 | pub unsafe extern "C" fn _sched_setparam() { 37 | unreachable!("_sched_setparam"); 38 | } 39 | 40 | #[no_mangle] 41 | pub unsafe extern "C" fn sched_yield() { 42 | // error stmt here because untested and sched_yield doesn't seeem to happen 43 | // except in failure case for our current applications... 44 | log::warn!("sched_yield called"); 45 | use lineup::tls2::Environment; 46 | Environment::thread().relinquish() 47 | } 48 | 49 | /// Restartable atomic sequences are code sequences which are guaranteed to 50 | /// execute without preemption. This property is assured by the kernel by 51 | /// re-executing a preempted sequence from the start. 52 | #[no_mangle] 53 | pub unsafe extern "C" fn rasctl(_addr: *mut c_void, _len: c_size_t, _op: c_int) -> c_int { 54 | errno::ENOSYS 55 | } 56 | -------------------------------------------------------------------------------- /lib/vibrio/src/rumprt/crt/signals.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! POSIX signals implementation 5 | //! 6 | //! Just very basic stubs for now. 7 | 8 | use crate::rumprt::{c_int, c_void}; 9 | 10 | /// C wrapper for `sigset_t` type. 11 | #[repr(C)] 12 | #[derive(Default, Debug, Copy, Clone)] 13 | pub struct SigSet { 14 | pub bits: [u32; 4usize], 15 | } 16 | 17 | /// Capable to store the different signal handler routines. 18 | /// 19 | /// C type wrapper for signal handler union in `struct sigaction`. 20 | #[repr(C)] 21 | #[derive(Copy, Clone)] 22 | pub union SigActionHandler { 23 | pub handler: Option, 24 | pub sigaction: Option, 25 | _bindgen_union_align: u64, 26 | } 27 | 28 | /// Signal vector "template" used in sigaction call. 29 | /// 30 | /// C wrapper for `struct sigaction`. 31 | #[repr(C)] 32 | #[derive(Copy, Clone)] 33 | pub struct SigAction { 34 | pub u: SigActionHandler, 35 | pub mask: SigSet, 36 | pub flags: c_int, 37 | } 38 | 39 | const SIG_IGN: u64 = 1; 40 | 41 | unsafe fn sigaction(_sig: c_int, _act: *const SigAction, oact: *mut SigAction) -> c_int { 42 | if !oact.is_null() { 43 | let sa: SigAction = SigAction { 44 | u: SigActionHandler { 45 | _bindgen_union_align: SIG_IGN, 46 | }, 47 | mask: Default::default(), 48 | flags: 0, 49 | }; 50 | *oact = sa; 51 | } 52 | 53 | 0 54 | } 55 | 56 | #[no_mangle] 57 | pub unsafe extern "C" fn _sys___sigprocmask14( 58 | _how: c_int, 59 | _set: *const SigSet, 60 | oset: *mut SigSet, 61 | ) -> c_int { 62 | if !oset.is_null() { 63 | *oset = Default::default(); 64 | } 65 | 0 66 | } 67 | 68 | #[no_mangle] 69 | pub unsafe extern "C" fn __sigaction14( 70 | sig: c_int, 71 | act: *const SigAction, 72 | oact: *mut SigAction, 73 | ) -> c_int { 74 | sigaction(sig, act, oact) 75 | } 76 | 77 | #[no_mangle] 78 | pub unsafe extern "C" fn ____sigtimedwait50() { 79 | unreachable!("____sigtimedwait50"); 80 | } 81 | 82 | #[no_mangle] 83 | pub unsafe extern "C" fn _sys___sigsuspend14() { 84 | unreachable!("_sys___sigsuspend14"); 85 | } 86 | -------------------------------------------------------------------------------- /lib/vibrio/src/rumprt/crt/tls.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Functions to manage thread-local storage. 5 | //! 6 | //! In our case this is already managed by lineup. 7 | 8 | #[no_mangle] 9 | pub unsafe extern "C" fn __libc_static_tls_setup() { 10 | /* NOP */ 11 | } 12 | 13 | #[no_mangle] 14 | pub unsafe extern "C" fn _rtld_tls_allocate() -> *mut u8 { 15 | unsafe { lineup::tls2::ThreadControlBlock::new_tls_area() as *mut u8 } 16 | } 17 | 18 | #[no_mangle] 19 | pub unsafe extern "C" fn _rtld_tls_free(tls_ptr: *mut u8) { 20 | /* NOP */ 21 | unreachable!() 22 | } 23 | -------------------------------------------------------------------------------- /lib/vibrio/src/rumprt/crt/unsupported.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use crate::rumprt::{c_int, errno}; 5 | 6 | #[no_mangle] 7 | pub unsafe extern "C" fn _sys_setcontext() -> c_int { 8 | errno::ENOTSUP 9 | } 10 | 11 | #[no_mangle] 12 | pub unsafe extern "C" fn _sys___wait450() -> c_int { 13 | errno::ENOTSUP 14 | } 15 | 16 | #[no_mangle] 17 | pub unsafe extern "C" fn setpriority() -> c_int { 18 | errno::ENOTSUP 19 | } 20 | -------------------------------------------------------------------------------- /lib/vibrio/src/rumprt/sp.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! The sp interface implementation, just stubs at the moment. 5 | 6 | use super::{c_int, c_size_t, c_void}; 7 | 8 | #[no_mangle] 9 | pub unsafe extern "C" fn rumpuser_sp_anonmmap( 10 | _arg: *mut c_void, 11 | _howmuch: c_size_t, 12 | _addr: *const *const c_void, 13 | ) { 14 | unreachable!("rumpuser_sp_anonmmap"); 15 | } 16 | 17 | #[no_mangle] 18 | pub unsafe extern "C" fn rumpuser_sp_copyin( 19 | _arg: *mut c_void, 20 | _raddr: *const c_void, 21 | _laddr: *mut c_void, 22 | _len: c_size_t, 23 | ) { 24 | unreachable!("rumpuser_sp_copyin"); 25 | } 26 | 27 | #[no_mangle] 28 | pub unsafe extern "C" fn rumpuser_sp_copyinstr( 29 | _arg: *mut c_void, 30 | _raddr: *const c_void, 31 | _laddr: *mut c_void, 32 | _dlen: *mut c_size_t, 33 | ) { 34 | unreachable!("rumpuser_sp_copyinstr"); 35 | } 36 | 37 | #[no_mangle] 38 | pub unsafe extern "C" fn rumpuser_sp_copyout( 39 | _arg: *mut c_void, 40 | _laddr: *const c_void, 41 | _raddr: *mut c_void, 42 | _dlen: c_size_t, 43 | ) { 44 | unreachable!("rumpuser_sp_copyout"); 45 | } 46 | 47 | #[no_mangle] 48 | pub unsafe extern "C" fn rumpuser_sp_copyoutstr( 49 | _arg: *mut c_void, 50 | _laddr: *const c_void, 51 | _raddr: *mut c_void, 52 | _dlen: *const c_size_t, 53 | ) { 54 | unreachable!("rumpuser_sp_copyoutstr"); 55 | } 56 | 57 | #[no_mangle] 58 | pub unsafe extern "C" fn rumpuser_sp_fini(_arg: *mut c_void) { 59 | unreachable!("rumpuser_sp_fini"); 60 | } 61 | 62 | #[no_mangle] 63 | pub unsafe extern "C" fn rumpuser_sp_init( 64 | _url: *const char, 65 | _ostype: *const char, 66 | _osrelease: *const char, 67 | _machine: *const char, 68 | ) { 69 | unreachable!("rumpuser_sp_init"); 70 | } 71 | 72 | #[no_mangle] 73 | pub unsafe extern "C" fn rumpuser_sp_raise(_arg: *mut c_void, _signo: c_int) { 74 | unreachable!("rumpuser_sp_raise"); 75 | } 76 | -------------------------------------------------------------------------------- /lib/vibrio/src/vconsole.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! A simple virtual console for user-space programs (getchar et. al.). 5 | //! 6 | //! Needs to be a proper serial driver. 7 | 8 | static COM1_IRQ: u64 = 4 + 32; 9 | 10 | pub fn init() { 11 | crate::syscalls::Irq::irqalloc(COM1_IRQ, 0).ok(); 12 | } 13 | 14 | fn _getchar() -> Option { 15 | None 16 | } 17 | -------------------------------------------------------------------------------- /lib/vibrio/src/writer.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! A simple printing infrastructure for user-space programs. 5 | //! We provide [`core::fmt::Write`] and [`log::Log`]. 6 | 7 | use core::{fmt, ops}; 8 | 9 | use log::{Level, Metadata, Record}; 10 | 11 | /// println macro that uses the logging syscall. 12 | #[macro_export] 13 | macro_rules! sys_println { 14 | ( $($arg:tt)* ) => ({ 15 | use core::fmt::Write; 16 | use $crate::writer::{Writer}; 17 | let _ = write!(&mut Writer::get(), $($arg)*); 18 | }) 19 | } 20 | 21 | /// print macro that uses the logging syscall. 22 | #[macro_export] 23 | macro_rules! sys_print { 24 | ( $($arg:tt)* ) => ({ 25 | use core::fmt::Write; 26 | use $crate::writer::{WriterNoDrop}; 27 | let _ = write!(&mut WriterNoDrop::get(), $($arg)*); 28 | }) 29 | } 30 | 31 | pub struct Writer; 32 | 33 | impl Writer { 34 | /// Obtain a logger for the specified module. 35 | pub fn get_module(module: &str) -> Writer { 36 | use core::fmt::Write; 37 | let mut ret = Writer; 38 | let _ = write!(&mut ret, "[{}] ", module); 39 | ret 40 | } 41 | 42 | pub fn get() -> Writer { 43 | Writer 44 | } 45 | } 46 | 47 | impl ops::Drop for Writer { 48 | /// Release the logger. 49 | fn drop(&mut self) { 50 | use core::fmt::Write; 51 | let _ = write!(self, "\r\n"); 52 | } 53 | } 54 | 55 | impl fmt::Write for Writer { 56 | /// Write stuff to serial out. 57 | fn write_str(&mut self, s: &str) -> fmt::Result { 58 | crate::syscalls::Process::print(s).expect("Can't write string"); 59 | Ok(()) 60 | } 61 | } 62 | 63 | pub struct WriterNoDrop; 64 | 65 | impl WriterNoDrop { 66 | pub fn get() -> WriterNoDrop { 67 | WriterNoDrop 68 | } 69 | } 70 | 71 | impl fmt::Write for WriterNoDrop { 72 | /// Write stuff to serial out. 73 | fn write_str(&mut self, s: &str) -> fmt::Result { 74 | crate::syscalls::Process::print(s).expect("Can't write string"); 75 | Ok(()) 76 | } 77 | } 78 | 79 | #[derive(Debug)] 80 | pub struct ULogger; 81 | 82 | pub static mut LOGGER: ULogger = ULogger {}; 83 | 84 | impl log::Log for ULogger { 85 | fn enabled(&self, metadata: &Metadata) -> bool { 86 | metadata.level() <= Level::Trace 87 | } 88 | 89 | fn log(&self, record: &Record) { 90 | if self.enabled(record.metadata()) { 91 | sys_println!( 92 | "[{}] - {}: {}", 93 | record.level(), 94 | record.target(), 95 | record.args(), 96 | ); 97 | } 98 | } 99 | 100 | fn flush(&self) {} 101 | } 102 | -------------------------------------------------------------------------------- /lib/vmxnet3/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vmxnet3" 3 | version = "0.1.0" 4 | authors = ["Gerd Zellweger "] 5 | edition = "2018" 6 | description = "vmxnet3 - a virtual NIC device driver" 7 | license = "BSD-2-Clause" 8 | 9 | [dependencies] 10 | log = "0.4" 11 | kpi = { path = "../kpi" } 12 | static_assertions = "1.1.0" 13 | x86 = { version = "0.52", features = ["unstable"] } 14 | arrayvec = { version = "0.7.0", default-features = false } 15 | custom_error = { version = "1.9", default-features = false, features = ["unstable"] } 16 | driverkit = "0.24" 17 | smoltcp = { version = "0.8.0", default-features = false, features = [ "alloc", "log", "proto-ipv4", "proto-igmp", "proto-dhcpv4", "socket-raw", "socket-icmp", "socket-udp", "socket-tcp", "medium-ethernet" ] } 18 | 19 | [target.'cfg(target_family = "unix")'.dev-dependencies] 20 | env_logger = "0.9" 21 | 22 | [features] 23 | # Enable receive-side-scaling (RSS) 24 | rss = [] 25 | -------------------------------------------------------------------------------- /lib/vmxnet3/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: BSD-2-Clause 3 | 4 | #![no_std] 5 | #![feature(core_intrinsics, allocator_api)] 6 | 7 | extern crate alloc; 8 | 9 | pub mod pci; 10 | pub mod reg; 11 | pub mod smoltcp; 12 | pub mod var; 13 | pub mod vmx; 14 | 15 | #[derive(Default)] 16 | pub struct BoundedU32(u32); 17 | 18 | impl BoundedU32<{ LOW }, { HIGH }> { 19 | pub const LOW: u32 = LOW; 20 | pub const HIGH: u32 = HIGH; 21 | 22 | pub fn new(n: u32) -> Self { 23 | BoundedU32(n.min(Self::HIGH).max(Self::LOW)) 24 | } 25 | 26 | pub fn fallible_new(n: u32) -> Result { 27 | match n { 28 | n if n < Self::LOW => Err("Value too low"), 29 | n if n > Self::HIGH => Err("Value too high"), 30 | n => Ok(BoundedU32(n)), 31 | } 32 | } 33 | 34 | pub fn set(&mut self, n: u32) { 35 | *self = BoundedU32(n.min(Self::HIGH).max(Self::LOW)) 36 | } 37 | } 38 | 39 | impl core::ops::Deref for BoundedU32<{ LOW }, { HIGH }> { 40 | type Target = u32; 41 | 42 | fn deref(&self) -> &Self::Target { 43 | &self.0 44 | } 45 | } 46 | 47 | #[derive(Default)] 48 | pub struct BoundedUSize(usize); 49 | 50 | impl BoundedUSize<{ LOW }, { HIGH }> { 51 | pub const LOW: usize = LOW; 52 | pub const HIGH: usize = HIGH; 53 | 54 | pub fn new(n: usize) -> Self { 55 | BoundedUSize(n.min(Self::HIGH).max(Self::LOW)) 56 | } 57 | 58 | pub fn fallible_new(n: usize) -> Result { 59 | match n { 60 | n if n < Self::LOW => Err("Value too low"), 61 | n if n > Self::HIGH => Err("Value too high"), 62 | n => Ok(BoundedUSize(n)), 63 | } 64 | } 65 | 66 | pub fn set(&mut self, n: usize) { 67 | *self = BoundedUSize(n.min(Self::HIGH).max(Self::LOW)) 68 | } 69 | } 70 | 71 | impl core::ops::Deref for BoundedUSize<{ LOW }, { HIGH }> { 72 | type Target = usize; 73 | 74 | fn deref(&self) -> &Self::Target { 75 | &self.0 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/vmxnet3/src/pvrdma/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: BSD-2-Clause 3 | 4 | //! PVRDMA device for VMs 5 | //! 6 | //! # Additional Documentation 7 | //! - https://github.com/qemu/qemu/blob/master/docs/pvrdma.txt 8 | //! - https://blog.linuxplumbersconf.org/2017/ocw/system/presentations/4730/original/lpc-2017-pvrdma-marcel-apfelbaum-yuval-shaia.pdf 9 | //! 10 | 11 | mod defs; 12 | mod pci; 13 | 14 | use alloc::boxed::Box; 15 | 16 | use custom_error::custom_error; 17 | use pci::BarAccess; 18 | 19 | custom_error! {pub PVRDMAError 20 | DeviceNotSupported = "Unknown device/version", 21 | InterruptModeNotSupported = "Device requested an interrupt mode that is not supported by driver", 22 | OutOfMemory = "Unable to allocate raw memory.", 23 | } 24 | 25 | pub struct PVRDMA { 26 | pci: BarAccess, 27 | 28 | /// Is link active? 29 | link_active: bool, 30 | } 31 | 32 | impl PVRDMA { 33 | pub fn new(nrx: usize, trx: usize) -> Result, PVRDMAError> { 34 | Err(PVRDMAError::OutOfMemory) 35 | } 36 | } 37 | 38 | /* 39 | static inline void pvrdma_write_reg(struct pvrdma_dev *dev, u32 reg, u32 val) 40 | { 41 | writel(cpu_to_le32(val), dev->regs + reg); 42 | } 43 | 44 | static inline u32 pvrdma_read_reg(struct pvrdma_dev *dev, u32 reg) 45 | { 46 | return le32_to_cpu(readl(dev->regs + reg)); 47 | } 48 | 49 | */ 50 | -------------------------------------------------------------------------------- /lib/vmxnet3/src/pvrdma/pci.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: BSD-2-Clause 3 | 4 | //! PCI Bars: 5 | //! BAR 0 - MSI-X 6 | //! MSI-X vectors: 7 | //! (0) Command - used when execution of a command is completed. 8 | //! (1) Async - not in use. 9 | //! (2) Completion - used when a completion event is placed in 10 | //! device's CQ ring. 11 | //! BAR 1 - Registers 12 | //! -------------------------------------------------------- 13 | //! | VERSION | DSR | CTL | REQ | ERR | ICR | IMR | MAC | 14 | //! -------------------------------------------------------- 15 | //! DSR - Address of driver/device shared memory used 16 | //! for the command channel, used for passing: 17 | //! - General info such as driver version 18 | //! - Address of 'command' and 'response' 19 | //! - Address of async ring 20 | //! - Address of device's CQ ring 21 | //! - Device capabilities 22 | //! CTL - Device control operations (activate, reset etc) 23 | //! IMG - Set interrupt mask 24 | //! REQ - Command execution register 25 | //! ERR - Operation status 26 | //! 27 | //! BAR 2 - UAR 28 | //! --------------------------------------------------------- 29 | //! | QP_NUM | SEND/RECV Flag || CQ_NUM | ARM/POLL Flag | 30 | //! --------------------------------------------------------- 31 | //! - Offset 0 used for QP operations (send and recv) 32 | //! - Offset 4 used for CQ operations (arm and poll) 33 | 34 | use crate::pci::{busread, buswrite, confread, confwrite, BarIO}; 35 | 36 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] 37 | pub struct BarAccess { 38 | /// Bus, device, function triplet of PCI device 39 | pci_addr: (u32, u32, u32), 40 | /// MSI-X 41 | bar0: u64, 42 | /// Registers 43 | bar1: u64, 44 | /// UAR 45 | bar2: u64, 46 | } 47 | 48 | impl BarAccess { 49 | pub(crate) fn new(bus: u32, dev: u32, fun: u32) -> Self { 50 | unsafe { 51 | //let devline = confread(bus, dev, fun, 0x0); 52 | //assert_eq!(devline, 0x7b015ad, "Sanity check for vmxnet3"); 53 | 54 | let bar0 = confread(bus, dev, fun, 0x10); 55 | let bar1 = confread(bus, dev, fun, 0x14); 56 | //let bar_msix = pci::confread(BUS, DEV, FUN, 0x7); 57 | 58 | log::debug!("BAR0 at: {:#x}", bar0); 59 | log::debug!("BAR1 at: {:#x}", bar1); 60 | //debug!("MSI-X at: {:#x}", bar_msi); 61 | 62 | BarAccess { 63 | pci_addr: (bus, dev, fun), 64 | bar0: bar0.into(), 65 | bar1: bar1.into(), 66 | bar2: 0x0, 67 | } 68 | } 69 | } 70 | } 71 | 72 | impl BarIO for BarAccess { 73 | fn read_bar0(&self, offset: u64) -> u32 { 74 | unsafe { busread(self.bar0, offset) } 75 | } 76 | 77 | fn write_bar0(&self, offset: u64, data: u32) { 78 | unsafe { buswrite(self.bar0, offset, data) }; 79 | } 80 | 81 | fn read_bar1(&self, offset: u64) -> u32 { 82 | unsafe { busread(self.bar1, offset) } 83 | } 84 | 85 | fn write_bar1(&self, offset: u64, data: u32) { 86 | unsafe { buswrite(self.bar1, offset, data) }; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-11-21" 3 | components = [ "rustfmt", "rustc-dev", "rust-src", "cargo", "clippy" ] 4 | profile = "default" 5 | -------------------------------------------------------------------------------- /scripts/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Dockerfile for the build container 3 | # 4 | FROM ubuntu:20.04 5 | LABEL maintainer="Reto Achermann " 6 | 7 | # arguments for this docker container 8 | # the user name and id of the container 9 | ARG arg_uid=1000 10 | ARG arg_user=user 11 | 12 | # set the environment arguments (will be used in the script) 13 | ENV ENV_USER=$arg_user 14 | ENV ENV_UID=$arg_uid 15 | 16 | # copy the enntrypoint and setup files into the image 17 | COPY docker-setup.sh /docker-setup.sh 18 | COPY generic-setup.sh /generic-setup.sh 19 | COPY docker-entrypoint.sh /entrypoint.sh 20 | 21 | # run the setup scripts 22 | RUN /bin/bash docker-setup.sh 23 | 24 | # set the user for this docker 25 | USER $arg_user 26 | 27 | # entrypoint for the docker image 28 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /scripts/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # 4 | # the docker entry point -- setup environment and execute command / drop into shell 5 | # 6 | 7 | echo "================================================" 8 | echo "Build docker container" 9 | echo "================================================" 10 | 11 | source /rustversion.sh 12 | 13 | # source the cargo environment 14 | source "$HOME/.cargo/env" 15 | 16 | # this is the docker entrypoint 17 | cd /source || exit 18 | 19 | 20 | echo "setting rust versions to ${RUST_VERSION}" 21 | cd kernel || exit 22 | rustup default "${RUST_VERSION}" 23 | cd .. 24 | rustup default "${RUST_VERSION}" 25 | 26 | # ensure rustup is up to date and we got the sources 27 | rustup component add rust-src 28 | rustup update 29 | 30 | if [ "$1" == "" ]; then 31 | echo "starting shell..." 32 | exec "/bin/bash" 33 | exit 0 34 | else 35 | echo "executing '$*'" 36 | exec "$*" 37 | fi -------------------------------------------------------------------------------- /scripts/docker-run.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # 4 | # runs or builds the docker container 5 | # 6 | # to force building, execute with 'force-build' 7 | # 8 | # Note: add yourself to the docker group (see website) to run this without root 9 | 10 | # the root directory (corresponds to the git) 11 | ROOT=$(git rev-parse --show-toplevel) 12 | 13 | # the user ID and name of the current user 14 | USER_ID=$(id -u) 15 | USER_NAME=$(whoami) 16 | 17 | # the image name to be built 18 | IMAGE=nrkbuild 19 | 20 | if [[ "$1" = "force-build" ]]; then 21 | echo "trigger force build (removing any existing image)" 22 | # remove the container 23 | docker container rm ${IMAGE} 24 | 25 | # remove the image 26 | docker image rm -f ${IMAGE} 27 | fi 28 | 29 | # check if there is such an image or 30 | if ! docker image ls | grep ${IMAGE} > /dev/null; then 31 | echo "docker image ${IMAGE} does not exist. building it." 32 | docker build --build-arg arg_uid="${USER_ID}" --build-arg arg_user="${USER_NAME}" \ 33 | -t ${IMAGE} "${ROOT}/scripts" 34 | fi 35 | 36 | # run the image interactively. we automatically mount the source directory in /source 37 | docker run -i -t --rm --name ${IMAGE} --mount type=bind,source="${ROOT}",target=/source ${IMAGE} 38 | -------------------------------------------------------------------------------- /scripts/docker-setup.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # 4 | # script used to configure the docker container 5 | # this runs inside docker to install required packages and create the user 6 | # 7 | 8 | set -exu 9 | 10 | source /generic-setup.sh 11 | 12 | export RUST_VERSION=nightly-2021-03-16 13 | echo "export RUST_VERSION=${RUST_VERSION}" > /rustversion.sh 14 | 15 | echo "installing dependencies..." 16 | install_build_dependencies 17 | 18 | # create the user and the directory 19 | groupadd -g "${ENV_UID}" "${ENV_USER}" 20 | useradd "${ENV_USER}" -u "${ENV_UID}" -g "${ENV_UID}" -m -s /bin/bash 21 | 22 | 23 | echo "switching to user ${ENV_USER}" 24 | export HOME=/home/${ENV_USER} 25 | 26 | su - "${ENV_USER}" 27 | cd "$HOME" 28 | 29 | # bootstrap rust 30 | bootstrap_rust 31 | install_rust_build_dependencies 32 | 33 | # now make sure everything is owned by the user 34 | chown -R "${ENV_USER}":"${ENV_USER}" "/home/${ENV_USER}" 35 | 36 | # make the entrypoint executable 37 | chmod 755 /entrypoint.sh 38 | -------------------------------------------------------------------------------- /scripts/generic-setup.sh: -------------------------------------------------------------------------------- 1 | # 2 | # functions to install the build and run dependencies 3 | # 4 | 5 | # do we need sudo, or are we already running as root? 6 | if [ ${EUID} != 0 ]; then 7 | echo "not running as root, using sudo" 8 | APT="sudo apt-get" 9 | else 10 | echo "running as root." 11 | APT="apt-get" 12 | fi 13 | 14 | 15 | function install_build_dependencies() 16 | { 17 | echo "installing build dependencies.." 18 | if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then 19 | $APT -o Acquire::Max-FutureTime=86400 update > /dev/null 20 | 21 | # installing python build dependencies 22 | $APT install -y python3 python3-pip python3-plumbum python3-prctl python3-toml python3-pexpect python3-packaging > /dev/null 23 | 24 | # nrk build dependencies 25 | $APT install -y uml-utilities mtools zlib1g-dev make gcc build-essential git curl > /dev/null 26 | 27 | # For building rump packages (rkapps) 28 | $APT install -y genisoimage > /dev/null 29 | fi 30 | } 31 | 32 | 33 | function install_run_dependencies() 34 | { 35 | echo "installing run dependencies..." 36 | if [ "$(uname)" == "Darwin" ]; then 37 | brew install qemu 38 | elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then 39 | # native build dependencies 40 | $APT install -y qemu qemu-kvm qemu-system-x86 sshpass hwloc libhwloc-dev numactl libevent-dev bridge-utils > /dev/null 41 | 42 | # nrk integration-test dependencies 43 | $APT install -y isc-dhcp-server socat netcat-openbsd redis-tools net-tools graphviz tcpdump libhugetlbfs-bin > /dev/null 44 | fi 45 | } 46 | 47 | 48 | function bootstrap_rust() 49 | { 50 | echo "bootstrapping rust..." 51 | 52 | if [ -f "$HOME/.cargo/env" ]; then 53 | source "$HOME/.cargo/env" 54 | fi 55 | 56 | # Make sure rust is up-to-date 57 | if [ ! -x "$(command -v rustup)" ] ; then 58 | curl https://sh.rustup.rs -sSf | sh -s -- -y 59 | fi 60 | 61 | source "$HOME/.cargo/env" 62 | rustup update 63 | } 64 | 65 | 66 | function install_rust_build_dependencies() 67 | { 68 | echo "rust build dependencies" 69 | 70 | # Install mdbook (used by docs/) 71 | if [ ! -x "$(command -v mdbook)" ]; then 72 | MDBOOK_FLAGS="" 73 | if [ "$CI" = true ] ; then 74 | # Reduce compile time by disabling `watch`, `serve` etc. commands 75 | # otherwise this takes >5min in CI: 76 | MDBOOK_FLAGS="--no-default-features" 77 | fi 78 | cargo install mdbook $MDBOOK_FLAGS --locked --version 0.4.35 79 | fi 80 | } 81 | 82 | 83 | function install_rust_run_dependencies() 84 | { 85 | # Install corealloc (used by run.py) -- only native 86 | if [ ! -x "$(command -v corealloc)" ]; then 87 | cargo install corealloc 88 | fi 89 | } 90 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ex 3 | 4 | source scripts/generic-setup.sh 5 | 6 | # system wide dependencies (packages) 7 | install_build_dependencies 8 | install_run_dependencies 9 | 10 | # installing rust 11 | bootstrap_rust 12 | install_rust_build_dependencies 13 | install_rust_run_dependencies 14 | 15 | # set permissions for tcpdump for vmxnet3 tests 16 | sudo setcap cap_net_raw,cap_net_admin=eip `which tcpdump` 17 | -------------------------------------------------------------------------------- /usr/init/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "init" 3 | version = "0.1.0" 4 | authors = ["Gerd Zellweger "] 5 | edition = "2021" 6 | build = "build.rs" 7 | license = "MIT OR Apache-2.0" 8 | 9 | [[bin]] 10 | name = "init" 11 | path = "src/init.rs" 12 | 13 | [dependencies] 14 | lineup = { path = "../../lib/lineup" } 15 | vibrio = { path = "../../lib/vibrio" } 16 | kpi = { path = "../../lib/kpi" } 17 | arrayvec = { version = "0.7.0", default-features = false } 18 | proptest = { git = "https://github.com/gz/proptest.git", branch = "x86-asm", default-features = false, features = ['alloc', 'hardware-rng'] } 19 | rawtime = "0.0.10" 20 | x86 = { version = "0.52", features = ["unstable"] } 21 | log = "0.4" 22 | #libm = "0.2.2" 23 | num-traits = { version = "0.2", default-features = false, features = ["libm"] } 24 | lazy_static = { version = "1.4", default_features = false } 25 | cstr_core = { version = "0.2.3", default-features = false } 26 | spin = { version = "0.5.2", default_features = false } 27 | hashbrown = { version = "0.11", features = [ "nightly" ] } 28 | md-5 = { version = "0.10.6", default-features = false } 29 | base64ct = "1.6.0" 30 | 31 | [features] 32 | default = [] 33 | rumprt = ["vibrio/rumprt"] 34 | # Use virtio instead of e1000 35 | virtio = [] 36 | 37 | # Tests we run with CI make sure that the base features of 38 | # the kernel are working: 39 | test-print = [] 40 | test-map = [] 41 | test-alloc = [] 42 | test-upcall = [] 43 | test-scheduler = [] 44 | test-scheduler-smp = [] 45 | test-syscalls = [] 46 | test-rump-tmpfs = ["rumprt"] 47 | test-rump-net = ["rumprt"] 48 | test-fs = [] 49 | test-fs-prop = [] 50 | test-pmem-alloc = [] 51 | test-phys-alloc = [] 52 | test-core-alloc = [] 53 | test-rackscale-shootdown = [] 54 | test-concurrent-shootdown = [] 55 | 56 | # Simple micro-benchmarks 57 | bench-vmops = [] 58 | bench-vmops-unmaplat = [] 59 | fxmark = [] 60 | memhash = [] 61 | 62 | # smoke: A way to tell the micro-benchmarks 63 | # to only run for a short period, don't consume many 64 | # resources, just enough to make sure they work 65 | # but won't produce valid results 66 | smoke = [] 67 | 68 | # Do latency measurements in benchmarks 69 | latency = [] 70 | 71 | all-tests = [ 72 | "test-print", 73 | "test-map", 74 | "test-alloc", 75 | "test-upcall", 76 | "test-scheduler", 77 | #"test-scheduler-smp", # Doesn't return 78 | "test-syscalls", 79 | "test-rump-tmpfs", 80 | "test-rump-net", 81 | "test-fs", 82 | "test-phys-alloc", 83 | "test-core-alloc", 84 | # "test-request-core-remote", TODO: used only for rackscale tests right now 85 | #"test-fs-prop", # needs userspace 86 | #"test-pmem-alloc", # needs SMP 87 | ] 88 | -------------------------------------------------------------------------------- /usr/init/README.md: -------------------------------------------------------------------------------- 1 | # Init 2 | 3 | The simplest user-space test program. 4 | 5 | ## Manual build 6 | 7 | Invoke: 8 | 9 | ``` 10 | cargo rustc -- -C link-arg=-nostartfiles -Clink-arg=-static -Clink-arg=-zmax-page-size=0x200000 11 | ``` -------------------------------------------------------------------------------- /usr/init/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | fn main() { 5 | #[cfg(feature = "rumprt")] 6 | rumprt_dependencies(); 7 | } 8 | 9 | #[allow(unused)] 10 | fn rumprt_dependencies() { 11 | let libs = [ 12 | "rump", 13 | "rumpvfs", 14 | "rumpdev", 15 | "rumpfs_tmpfs", 16 | "rumpnet_config", 17 | "rumpnet", 18 | "rumpdev_bpf", 19 | "rumpdev_vnd", 20 | "rumpdev_rnd", 21 | //"rumprunfs_base", 22 | "rumpnet_netinet", 23 | "rumpnet_net", 24 | "rumpnet_netinet6", 25 | "rumpnet_local", 26 | "rumpfs_ffs", 27 | "rumpfs_cd9660", 28 | "rumpfs_ext2fs", 29 | "rumpdev_disk", 30 | "rumpdev_virtio_if_vioif", 31 | "rumpdev_virtio_ld", 32 | "rumpdev_virtio_viornd", 33 | "rumpdev_pci_virtio", 34 | "rumpdev_pci", 35 | "rumpdev_virtio_vioscsi", 36 | "rumpdev_scsipi", 37 | "rumpdev_audio", 38 | "rumpdev_audio_ac97", 39 | "rumpdev_pci_auich", 40 | "rumpdev_pci_eap", 41 | "rumpdev_pci_hdaudio", 42 | "rumpdev_hdaudio_hdafg", 43 | "rumpdev_pci_if_wm", 44 | "rumpdev_miiphy", 45 | "rumpdev_pci_usbhc", 46 | "rumpdev_usb", 47 | "rumpdev_umass", 48 | ]; 49 | 50 | for lib in libs { 51 | println!("cargo:rustc-link-lib=static:+whole-archive={}", lib); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /usr/init/src/fxmark/drbh.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use crate::fxmark::{Bench, PAGE_SIZE}; 5 | use alloc::vec; 6 | use alloc::vec::Vec; 7 | use core::sync::atomic::{AtomicUsize, Ordering}; 8 | use vibrio::io::*; 9 | 10 | #[derive(Clone)] 11 | pub struct DRBH { 12 | page: Vec, 13 | } 14 | 15 | impl Default for DRBH { 16 | fn default() -> DRBH { 17 | let page = vec![0xb; PAGE_SIZE as usize]; 18 | DRBH { page } 19 | } 20 | } 21 | 22 | impl Bench for DRBH { 23 | fn init(&self, _cores: Vec, _open_files: usize) { 24 | // Open a shared file for each core. 25 | let fd = vibrio::syscalls::Fs::open( 26 | "file.txt", 27 | FileFlags::O_RDWR | FileFlags::O_CREAT, 28 | FileModes::S_IRWXU, 29 | ) 30 | .expect("FileOpen syscall failed"); 31 | 32 | // Write a single page to the file at offset 0. 33 | let ret = 34 | vibrio::syscalls::Fs::write_at(fd, &self.page, 0).expect("FileWriteAt syscall failed"); 35 | assert_eq!(ret, PAGE_SIZE as u64); 36 | 37 | vibrio::syscalls::Fs::close(fd).expect("FileClose syscall failed"); 38 | } 39 | 40 | fn run( 41 | &self, 42 | poor_mans_barrier: &AtomicUsize, 43 | duration: u64, 44 | _core: usize, 45 | _write_ratio: usize, 46 | ) -> Vec { 47 | use vibrio::io::*; 48 | let mut iops_per_second = Vec::with_capacity(duration as usize); 49 | 50 | // Load fd from a shared struct. 51 | let fd = vibrio::syscalls::Fs::open( 52 | "file.txt", 53 | FileFlags::O_RDWR | FileFlags::O_CREAT, 54 | FileModes::S_IRWXU, 55 | ) 56 | .expect("FileOpen syscall failed"); 57 | let page: &mut [u8; PAGE_SIZE as usize] = &mut [0; PAGE_SIZE as usize]; 58 | 59 | // Synchronize with all cores 60 | poor_mans_barrier.fetch_sub(1, Ordering::Release); 61 | while poor_mans_barrier.load(Ordering::Acquire) != 0 { 62 | core::hint::spin_loop(); 63 | } 64 | 65 | let mut iops = 0; 66 | let mut iterations = 0; 67 | while iterations <= duration { 68 | let start = rawtime::Instant::now(); 69 | while start.elapsed().as_secs() < 1 { 70 | for _i in 0..64 { 71 | // Read a page from the shared file at offset 0. 72 | if vibrio::syscalls::Fs::read_at(fd, page, 0) 73 | .expect("FileReadAt syscall failed") 74 | != PAGE_SIZE 75 | { 76 | panic!("DRBH: read_at() failed"); 77 | } 78 | iops += 1; 79 | } 80 | } 81 | iops_per_second.push(iops); 82 | iterations += 1; 83 | iops = 0; 84 | } 85 | 86 | poor_mans_barrier.fetch_add(1, Ordering::Relaxed); 87 | iops_per_second.clone() 88 | } 89 | } 90 | 91 | unsafe impl Sync for DRBH {} 92 | -------------------------------------------------------------------------------- /usr/init/src/fxmark/drbl.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use crate::fxmark::{Bench, PAGE_SIZE}; 5 | use alloc::vec::Vec; 6 | use alloc::{format, vec}; 7 | use core::cell::RefCell; 8 | use core::sync::atomic::{AtomicUsize, Ordering}; 9 | use kpi::process::MAX_CORES; 10 | use lineup::core_id_to_index; 11 | use vibrio::io::*; 12 | 13 | #[derive(Clone)] 14 | pub struct DRBL { 15 | page: Vec, 16 | fds: RefCell>, 17 | } 18 | 19 | impl Default for DRBL { 20 | fn default() -> DRBL { 21 | let page = vec![0xb; PAGE_SIZE as usize]; 22 | let fd = vec![u64::MAX; MAX_CORES]; 23 | DRBL { 24 | page, 25 | fds: RefCell::new(fd), 26 | } 27 | } 28 | } 29 | 30 | impl Bench for DRBL { 31 | fn init(&self, cores: Vec, _open_files: usize) { 32 | for core in cores { 33 | let fd = vibrio::syscalls::Fs::open( 34 | format!("file{}.txt", core), 35 | FileFlags::O_RDWR | FileFlags::O_CREAT, 36 | FileModes::S_IRWXU, 37 | ) 38 | .expect("FileOpen syscall failed"); 39 | 40 | // This call is to tests nrk memory deallocator for large allocations. 41 | let ret = vibrio::syscalls::Fs::write_at(fd, &self.page, 0) 42 | .expect("FileWriteAt syscall failed"); 43 | assert_eq!(ret, PAGE_SIZE as u64); 44 | self.fds.borrow_mut()[core_id_to_index(core)] = fd; 45 | } 46 | } 47 | 48 | fn run( 49 | &self, 50 | poor_mans_barrier: &AtomicUsize, 51 | duration: u64, 52 | core: usize, 53 | _write_ratio: usize, 54 | ) -> Vec { 55 | let mut iops_per_second = Vec::with_capacity(duration as usize); 56 | let fd = self.fds.borrow()[core_id_to_index(core)]; 57 | if fd == u64::MAX { 58 | panic!("Unable to open a file"); 59 | } 60 | let page: &mut [u8; PAGE_SIZE as usize] = &mut [0; PAGE_SIZE as usize]; 61 | 62 | // Synchronize with all cores 63 | poor_mans_barrier.fetch_sub(1, Ordering::Release); 64 | while poor_mans_barrier.load(Ordering::Acquire) != 0 { 65 | core::hint::spin_loop(); 66 | } 67 | 68 | let mut iops = 0; 69 | let mut iterations = 0; 70 | while iterations <= duration { 71 | let start = rawtime::Instant::now(); 72 | while start.elapsed().as_secs() < 1 { 73 | for _i in 0..64 { 74 | if vibrio::syscalls::Fs::read_at(fd, page, 0) 75 | .expect("FileReadAt syscall failed") 76 | != PAGE_SIZE 77 | { 78 | panic!("DRBL: read_at() failed"); 79 | } 80 | iops += 1; 81 | } 82 | } 83 | iops_per_second.push(iops); 84 | iterations += 1; 85 | iops = 0; 86 | } 87 | 88 | poor_mans_barrier.fetch_add(1, Ordering::Relaxed); 89 | iops_per_second.clone() 90 | } 91 | } 92 | 93 | unsafe impl Sync for DRBL {} 94 | -------------------------------------------------------------------------------- /usr/init/src/fxmark/mwrl.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use crate::fxmark::Bench; 5 | use alloc::vec::Vec; 6 | use alloc::{format, vec}; 7 | use core::sync::atomic::{AtomicUsize, Ordering}; 8 | use vibrio::io::*; 9 | 10 | #[derive(Clone, Default)] 11 | pub struct MWRL {} 12 | 13 | impl Bench for MWRL { 14 | fn init(&self, cores: Vec, _open_files: usize) { 15 | for core in cores { 16 | let fd = vibrio::syscalls::Fs::open( 17 | format!("/{}/file-0.txt", core), 18 | FileFlags::O_RDWR | FileFlags::O_CREAT, 19 | FileModes::S_IRWXU, 20 | ) 21 | .expect("FileOpen syscall failed"); 22 | 23 | // Close the file. 24 | vibrio::syscalls::Fs::close(fd).expect("FileClose syscall failed"); 25 | } 26 | } 27 | 28 | fn run( 29 | &self, 30 | poor_mans_barrier: &AtomicUsize, 31 | duration: u64, 32 | core: usize, 33 | _write_ratio: usize, 34 | ) -> Vec { 35 | let mut iops_per_second = Vec::with_capacity(duration as usize); 36 | 37 | // Synchronize with all cores 38 | poor_mans_barrier.fetch_sub(1, Ordering::Release); 39 | while poor_mans_barrier.load(Ordering::Acquire) != 0 { 40 | core::hint::spin_loop(); 41 | } 42 | 43 | let mut iops = 0; 44 | let mut iterations = 0; 45 | let mut iter = 0; 46 | let filenames = vec![ 47 | format!("/{}/file-{}.txt", core, 0), 48 | format!("/{}/file-{}.txt", core, 1), 49 | ]; 50 | while iterations <= duration { 51 | let start = rawtime::Instant::now(); 52 | while start.elapsed().as_secs() < 1 { 53 | for _i in 0..64 { 54 | let old_name = iter % 2; 55 | iter += 1; 56 | let new_name = iter % 2; 57 | // Rename the file 58 | vibrio::syscalls::Fs::rename( 59 | filenames[old_name].as_str(), 60 | filenames[new_name].as_str(), 61 | ) 62 | .expect("FileRename syscall failed"); 63 | iops += 1; 64 | } 65 | } 66 | iops_per_second.push(iops); 67 | iterations += 1; 68 | iops = 0; 69 | } 70 | 71 | poor_mans_barrier.fetch_add(1, Ordering::Relaxed); 72 | iops_per_second.clone() 73 | } 74 | } 75 | 76 | unsafe impl Sync for MWRL {} 77 | -------------------------------------------------------------------------------- /usr/init/src/tests.rs: -------------------------------------------------------------------------------- 1 | pub(crate) fn syscalls() { 2 | kpi::syscalls::test_calls(); 3 | } 4 | -------------------------------------------------------------------------------- /usr/rkapps/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rkapps" 3 | version = "0.0.1" 4 | authors = ["Gerd Zellweger "] 5 | edition = "2018" 6 | build = "build.rs" 7 | links = "rumpkernel" 8 | 9 | [dependencies] 10 | rumpkernel = "0.0.5" 11 | vibrio = { path = "../../lib/vibrio", features = ["rumprt"] } 12 | 13 | [build-dependencies] 14 | num_cpus = "1.9" 15 | 16 | [features] 17 | redis = [] 18 | memcached = [] 19 | nginx = [] 20 | leveldb-bench = [] 21 | memcached-bench = [] 22 | monetdb = [] 23 | 24 | -------------------------------------------------------------------------------- /usr/rkapps/README.md: -------------------------------------------------------------------------------- 1 | # rkapps 2 | 3 | A wrapper to easily build applications already ported to run on top of rumpkernel for nrk 4 | (uses the following repo ). 5 | 6 | Check `build.rs` for steps. 7 | 8 | ## redis 9 | 10 | If we want to invoke a build manually: 11 | 12 | ```bash 13 | cd redis 14 | cd target/x86_64-nrk-none/debug/build/rkapps-$HASH/out/redis 15 | export RUMPRUN_TOOLCHAIN_TUPLE=x86_64-rumprun-netbsd 16 | export PATH=`realpath ../../../rumpkernel-$HASH/out/rumprun/bin`:$PATH 17 | make 18 | rumprun-bake nrk_generic redis.out ./bin/redis-server 19 | ``` 20 | 21 | ## memcached 22 | 23 | ```bash 24 | cd "target/x86_64-nrk-none/release/build/rkapps-8a4ead00329ed64e/out/memcached" 25 | PATH=target/x86_64-nrk-none/release/build/rumpkernel-934f79a93edbe559/out/rumprun/bin:$PATH RUMPRUN_TOOLCHAIN_TUPLE=x86_64-rumprun-netbsd make -j 12 26 | PATH=target/x86_64-nrk-none/release/build/rumpkernel-934f79a93edbe559/out/rumprun/bin:$PATH RUMPRUN_TOOLCHAIN_TUPLE=x86_64-rumprun-netbsd rumprun-bake nrk_generic ../../../../memcached.bin build/memcached 27 | ``` 28 | -------------------------------------------------------------------------------- /usr/rkapps/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 VMware, Inc. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | #![feature(lang_items, core_intrinsics)] 5 | #![feature(start)] 6 | #![no_std] 7 | #![no_main] 8 | use core::intrinsics; 9 | use core::panic::PanicInfo; 10 | 11 | extern crate vibrio; 12 | 13 | // Entry point for this program. 14 | #[no_mangle] // ensure that this symbol is called `main` in the output 15 | pub extern "C" fn rump_main1(_argc: i32, _argv: *const *const u8) -> i32 { 16 | 0 17 | } 18 | -------------------------------------------------------------------------------- /usr/x86_64-nrk-none.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": "", 3 | "dynamic-linking": false, 4 | "llvm-target": "x86_64-unknown-nrk-none", 5 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", 6 | "target-endian": "little", 7 | "target-pointer-width": "64", 8 | "target-c-int-width": "32", 9 | "linker": "ld", 10 | "linker-flavor": "ld", 11 | "os": "nrk", 12 | "arch": "x86_64", 13 | "disable-redzone": false, 14 | "features": "+sse", 15 | "position-independent-executables": true, 16 | "executables": true 17 | } --------------------------------------------------------------------------------