diff --git a/.cargo/config.toml b/.cargo/config.toml index 9ed6285..079ec3d 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,12 +5,17 @@ # so they only affect the final binary and don't break proc-macro or build-script linking. [target.'cfg(target_os = "linux")'] # Suppress .eh_frame emission from our own codegen. -rustflags = ["-C", "force-unwind-tables=no"] +rustflags = [ "-C", "force-unwind-tables=no" ] [target.x86_64-unknown-linux-gnu] -linker = "scripts/clang-wild" -rustflags = ["-C", "force-unwind-tables=no"] +linker = "scripts/clang-wild" +rustflags = [ "-C", "force-unwind-tables=no" ] [target.aarch64-unknown-linux-gnu] -linker = "scripts/clang-wild" -rustflags = ["-C", "force-unwind-tables=no"] +linker = "scripts/clang-wild" +rustflags = [ "-C", "force-unwind-tables=no" ] + +# rustc links these as PIE by default, but `__start` applies no relocations +# and never sets up $gp, so PIC code would read a GOT that does not exist. +[target.'cfg(any(target_arch = "mips", target_arch = "mips64"))'] +rustflags = [ "-C", "relocation-model=static" ] diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a1067c4..1ba4475 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,14 +1,28 @@ version: 2 updates: - # Update Cargo deps - package-ecosystem: cargo - directory: "/" + directory: / schedule: - interval: "weekly" + interval: weekly + cooldown: + default-days: 7 - # Update used workflows - package-ecosystem: github-actions - directory: "/" + directory: / schedule: - interval: daily + interval: weekly + cooldown: + default-days: 7 + exclude: [manic-systems/*] + groups: + actions: + patterns: ["*"] + - package-ecosystem: nix + directory: / + schedule: + interval: weekly + cooldown: + default-days: 7 + commit-message: + prefix: flake diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5f7a55f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,132 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + merge_group: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name != 'push' }} + +jobs: + checks: + name: Checks (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, ubuntu-26.04-arm, macos-latest] + uses: manic-systems/workflows/.github/workflows/rust-checks.yml@4d2d4a73ac933d23f00fb7a17dd39569f8e1c1dc # v2.3.2 + with: + os: ${{ matrix.os }} + flake-check: false + fmt: ${{ matrix.os == 'ubuntu-latest' }} + fmt-command: cargo fmt --all --check && taplo fmt --check + clippy: true + clippy-command: cargo clippy --locked --workspace --all-targets -- -D warnings + test: true + test-command: >- + cargo build --locked && + cargo test --locked --workspace --exclude microfetch + + cross: + name: Cross (${{ matrix.target }}) + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + toolchain: stable + - target: aarch64-unknown-linux-gnu + toolchain: stable + - target: riscv64gc-unknown-linux-gnu + toolchain: stable + - target: loongarch64-unknown-linux-gnu + toolchain: stable + - target: s390x-unknown-linux-gnu + toolchain: stable + # powerpc64 uses experimental asm features + - target: powerpc64le-unknown-linux-gnu + toolchain: nightly + - target: powerpc64-unknown-linux-gnu + toolchain: nightly + - target: armv7-unknown-linux-gnueabihf + toolchain: stable + # riscv32 is tier-3 + - target: riscv32gc-unknown-linux-gnu + toolchain: nightly + build-std: true + # sparc64 uses experimental asm features + - target: sparc64-unknown-linux-gnu + toolchain: nightly + # mips64 is tier-3 and uses experimental asm features + - target: mips64-unknown-linux-gnuabi64 + toolchain: nightly + build-std: true + - target: i686-unknown-linux-gnu + toolchain: stable + # powerpc uses experimental asm features + - target: powerpc-unknown-linux-gnu + toolchain: nightly + # mips is tier-3 and uses experimental asm features + - target: mips-unknown-linux-gnu + toolchain: nightly + build-std: true + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Set up Rust + uses: actions-rust-lang/setup-rust-toolchain@ecabd13d1c56bd1345c230e542e9144811ad706f # v2.0.0 + with: + toolchain: ${{ matrix.toolchain }} + target: ${{ !matrix.build-std && matrix.target || '' }} + components: ${{ matrix.build-std && 'rust-src' || '' }} + + - name: Install wild + uses: wild-linker/action@dc926c45399e1842cf81e604f52bdf0ad86a0c09 # v0.10.0 + + - name: Put wild on PATH + run: echo "$RUNNER_TEMP/wild-install" >> "$GITHUB_PATH" + + - name: Set up cross toolchain + uses: taiki-e/setup-cross-toolchain-action@12b7ad4acfa95a1476779d6c06699b96ec1691f8 # v1.42.0 + with: + target: ${{ matrix.target }} + + - name: Build + env: + TARGET: ${{ matrix.target }} + BUILD_STD: ${{ matrix.build-std && 'core,alloc,panic_abort' || '' }} + run: cargo build --locked --target "$TARGET" ${BUILD_STD:+-Zbuild-std="$BUILD_STD"} + + # tier-3 targets have no prebuilt std and tests are arch-agnostic, so + # run them against the host toolchain instead of the cross target. + - name: Test + env: + HOST_TARGET: ${{ matrix.build-std && 'x86_64-unknown-linux-gnu' || '' }} + run: cargo test --locked --workspace --exclude microfetch ${HOST_TARGET:+--target "$HOST_TARGET"} + + actions: + name: Actions Lint + uses: manic-systems/workflows/.github/workflows/actions-lint.yml@4d2d4a73ac933d23f00fb7a17dd39569f8e1c1dc # v2.3.2 + + required: + name: Required Checks + if: always() + needs: + - checks + - cross + - actions + runs-on: ubuntu-latest + steps: + - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + run: exit 1 diff --git a/.github/workflows/hotpath-benchmark.yml b/.github/workflows/hotpath-benchmark.yml index 3cc4217..60e3f85 100644 --- a/.github/workflows/hotpath-benchmark.yml +++ b/.github/workflows/hotpath-benchmark.yml @@ -18,16 +18,15 @@ jobs: env: HOTPATH_BENCHMARK: microfetch steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false ref: ${{ github.event.pull_request.head.sha || github.sha }} - - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - rustflags: "" + - uses: actions-rust-lang/setup-rust-toolchain@ecabd13d1c56bd1345c230e542e9144811ad706f # v2.0.0 - name: Install the wild linker - uses: wild-linker/action@v0.10.0 + uses: wild-linker/action@dc926c45399e1842cf81e604f52bdf0ad86a0c09 # v0.10.0 - name: Put wild on PATH run: echo "$RUNNER_TEMP/wild-install" >> "$GITHUB_PATH" @@ -53,7 +52,7 @@ jobs: cargo run -q --release -p microfetch-bench --example hotpath \ --features hotpath,hotpath-alloc,hotpath-cloud - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 if: github.event_name == 'pull_request' with: name: hotpath-report diff --git a/.github/workflows/hotpath-relay.yml b/.github/workflows/hotpath-relay.yml index 818cf09..4ffbe43 100644 --- a/.github/workflows/hotpath-relay.yml +++ b/.github/workflows/hotpath-relay.yml @@ -1,14 +1,14 @@ name: hotpath-relay on: - workflow_run: + workflow_run: # zizmor: ignore[dangerous-triggers] hotpath relays the PR report artifact workflows: ["hotpath-benchmark"] types: - completed jobs: relay: - uses: pawurb/hotpath-rs/.github/workflows/hotpath-relay.yml@v0.28.5 + uses: pawurb/hotpath-rs/.github/workflows/hotpath-relay.yml@3c6a2b5dd994da3db5a3d23e1cc6b91c542bec2a # v0.28.5 permissions: actions: read id-token: write diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index c699a69..0000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,114 +0,0 @@ -name: Rust - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -env: - CARGO_TERM_COLOR: always - -jobs: - test: - name: Test on ${{ matrix.target }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - target: x86_64-unknown-linux-gnu - toolchain: stable - - target: aarch64-unknown-linux-gnu - toolchain: stable - - target: riscv64gc-unknown-linux-gnu - toolchain: stable - - target: loongarch64-unknown-linux-gnu - toolchain: stable - - target: s390x-unknown-linux-gnu - toolchain: stable - # powerpc64 uses experimental asm features - - target: powerpc64le-unknown-linux-gnu - toolchain: nightly - - target: powerpc64-unknown-linux-gnu - toolchain: nightly - - target: armv7-unknown-linux-gnueabihf - toolchain: stable - # riscv32 is tier-3 - - target: riscv32gc-unknown-linux-gnu - toolchain: nightly - components: rust-src - build_std: true - # sparc64 uses experimental asm features - - target: sparc64-unknown-linux-gnu - toolchain: nightly - # mips64 is tier-3 and uses experimental asm features - - target: mips64-unknown-linux-gnuabi64 - toolchain: nightly - components: rust-src - build_std: true - - target: i686-unknown-linux-gnu - toolchain: stable - # powerpc uses experimental asm features - - target: powerpc-unknown-linux-gnu - toolchain: nightly - # mips is tier-3 and uses experimental asm features - - target: mips-unknown-linux-gnu - toolchain: nightly - components: rust-src - build_std: true - - steps: - - name: "Checkout" - uses: actions/checkout@v7 - - - name: "Setup Rust toolchain" - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - toolchain: ${{ matrix.toolchain }} - components: ${{ matrix.components || '' }} - rustflags: "" - - - name: "Add Rust target" - if: ${{ !matrix.build_std }} - run: rustup target add ${{ matrix.target }} - - - name: "Install the wild linker" - uses: wild-linker/action@v0.10.0 - - name: "Put wild on PATH" - run: echo "$RUNNER_TEMP/wild-install" >> "$GITHUB_PATH" - - - name: "Setup cross-compilation toolchain" - uses: taiki-e/setup-cross-toolchain-action@v1 - with: - target: ${{ matrix.target }} - - - name: "Build" - run: cargo build --verbose --target ${{ matrix.target }} ${{ matrix.build_std && '-Z build-std=core,alloc,panic_abort' || '' }} ${{ matrix.extra_args || '' }} - - # tier-3 targets have no prebuilt std and tests are arch-agnostic, so - # run them against the host toolchain instead of the cross target. - - name: "Run tests" - run: cargo test --workspace --exclude microfetch --verbose ${{ matrix.build_std && '--target x86_64-unknown-linux-gnu' || '' }} - - # macOS is libSystem-backed (no raw syscalls, no static linking), so it - # builds natively on an Apple Silicon runner rather than cross-compiling. - build-macos: - name: Test on aarch64-apple-darwin - runs-on: macos-14 - steps: - - name: "Checkout" - uses: actions/checkout@v7 - - - name: "Setup Rust toolchain" - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - toolchain: stable - target: aarch64-apple-darwin - rustflags: "" - - - name: "Build" - run: cargo build --verbose --target aarch64-apple-darwin - - - name: "Run tests" - run: cargo test --workspace --exclude microfetch --verbose diff --git a/Cargo.lock b/Cargo.lock index a5efb0e..edce76d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -208,8 +208,6 @@ dependencies = [ "num-traits", "oorandom", "page_size", - "plotters", - "rayon", "regex", "serde", "serde_json", @@ -217,16 +215,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "criterion-cycles-per-byte" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5396de42a52e9e5d8f67ef0702dae30451f310a9ba1c3094dcf228f0be0e54bc" -dependencies = [ - "cfg-if", - "criterion", -] - [[package]] name = "criterion-plot" version = "0.8.2" @@ -246,25 +234,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -626,7 +595,6 @@ name = "microfetch-bench" version = "1.2.0" dependencies = [ "criterion", - "criterion-cycles-per-byte", "hotpath", "microfetch-lib", ] @@ -688,34 +656,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "plotters" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" - -[[package]] -name = "plotters-svg" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" -dependencies = [ - "plotters-backend", -] - [[package]] name = "potential_utf" version = "0.1.6" @@ -773,26 +713,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "rayon" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "regex" version = "1.12.3" diff --git a/Cargo.toml b/Cargo.toml index 3b703c0..ba00fb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,38 +12,51 @@ version = "1.2.0" microfetch-asm = { path = "./crates/asm", version = "1.2.0" } microfetch-lib = { path = "./crates/lib", version = "1.2.0" } -criterion = { default-features = false, features = [ "cargo_bench_support" ], version = "0.8.2" } -criterion-cycles-per-byte = "0.8.0" +criterion = { default-features = false, features = [ "cargo_bench_support" ], version = "0.8.2" } [workspace.lints.clippy] -complexity = { level = "warn", priority = -1 } -nursery = { level = "warn", priority = -1 } -pedantic = { level = "warn", priority = -1 } -perf = { level = "warn", priority = -1 } -style = { level = "warn", priority = -1 } - -absolute_paths = "allow" -arbitrary_source_item_ordering = "allow" -implicit_return = "allow" -missing_docs_in_private_items = "allow" -non_ascii_literal = "allow" -pattern_type_mismatch = "allow" -print_stdout = "allow" -question_mark_used = "allow" -similar_names = "allow" -single_call_fn = "allow" -std_instead_of_core = "allow" -too_long_first_doc_paragraph = "allow" -too_many_lines = "allow" -unused_trait_names = "allow" +complexity = { level = "warn", priority = -1 } +nursery = { level = "warn", priority = -1 } +pedantic = { level = "warn", priority = -1 } +perf = { level = "warn", priority = -1 } +restriction = { level = "warn", priority = -1 } +style = { level = "warn", priority = -1 } + +blanket_clippy_restriction_lints = "allow" + +arbitrary_source_item_ordering = "allow" +arithmetic_side_effects = "allow" +cfg_not_test = "allow" +exhaustive_enums = "allow" +exhaustive_structs = "allow" +implicit_return = "allow" +indexing_slicing = "allow" +inline_asm_x86_intel_syntax = "allow" +inline_modules = "allow" +integer_division = "allow" +integer_division_remainder_used = "allow" +missing_docs_in_private_items = "allow" +missing_inline_in_public_items = "allow" +multiple_unsafe_ops_per_block = "allow" +pattern_type_mismatch = "allow" +pub_with_shorthand = "allow" +question_mark_used = "allow" +semicolon_inside_block = "allow" +separated_literal_suffix = "allow" +similar_names = "allow" +single_call_fn = "allow" +undocumented_unsafe_blocks = "allow" [profile.dev] +# nix's compiler_builtins carries compiler-rt objects that need libc, and only +# LTO keeps a debug link from pulling them in sadly +lto = "fat" opt-level = 1 panic = "abort" [profile.release] codegen-units = 1 -lto = true +lto = "fat" opt-level = "s" panic = "abort" strip = true diff --git a/crates/asm/src/aarch64.rs b/crates/asm/src/aarch64.rs index 6997f62..fce16cc 100644 --- a/crates/asm/src/aarch64.rs +++ b/crates/asm/src/aarch64.rs @@ -1,33 +1,32 @@ //! Syscall implementations for `aarch64`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { - let fd: i64; - core::arch::asm!( + let ret: i32; + asm!( "svc #0", - in("x8") 56i64, // SYS_openat - in("x0") -100i32, // AT_FDCWD + in("x8") 56_i64, // SYS_openat + in("x0") -100_i32, // AT_FDCWD in("x1") path, in("x2") flags, - in("x3") 0i32, // mode - lateout("x0") fd, + in("x3") 0_i32, // mode + lateout("x0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - fd as i32 - } + ret } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "svc #0", - in("x8") 63i64, // SYS_read + in("x8") 63_i64, // SYS_read in("x0") fd, in("x1") buf, in("x2") count, @@ -35,19 +34,16 @@ pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "svc #0", - in("x8") 64i64, // SYS_write + in("x8") 64_i64, // SYS_write in("x0") fd, in("x1") buf, in("x2") count, @@ -55,70 +51,58 @@ pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "svc #0", - in("x8") 57i64, // SYS_close + in("x8") 57_i64, // SYS_close in("x0") fd, lateout("x0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "svc #0", - in("x8") 160i64, // SYS_uname + in("x8") 160_i64, // SYS_uname in("x0") buf, lateout("x0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "svc #0", - in("x8") 43i64, // SYS_statfs + in("x8") 43_i64, // SYS_statfs in("x0") path, in("x1") buf, lateout("x0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i64; - core::arch::asm!( + asm!( "svc #0", in("x8") 179_i64, // __NR_sysinfo in("x0") info, @@ -129,34 +113,31 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "svc #0", - in("x8") 123i64, // __NR_sched_getaffinity + in("x8") 123_i64, // __NR_sched_getaffinity in("x0") pid, in("x1") mask_size, in("x2") mask, lateout("x0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "svc #0", - in("x8") 93i64, // SYS_exit + in("x8") 93_i64, // SYS_exit in("x0") code, options(noreturn, nostack) ); diff --git a/crates/asm/src/arm.rs b/crates/asm/src/arm.rs index 892b012..4493f4a 100644 --- a/crates/asm/src/arm.rs +++ b/crates/asm/src/arm.rs @@ -1,16 +1,18 @@ //! Syscall implementations for `arm`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "svc #0", - in("r7") 5i32, // SYS_open + in("r7") 5_i32, // SYS_open in("r0") path, in("r1") flags, - in("r2") 0i32, // mode + in("r2") 0_i32, // mode lateout("r0") ret, options(nostack) ); @@ -18,44 +20,44 @@ pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "svc #0", - in("r7") 3i32, // SYS_read + in("r7") 3_i32, // SYS_read in("r0") fd, in("r1") buf, in("r2") count, lateout("r0") ret, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "svc #0", - in("r7") 4i32, // SYS_write + in("r7") 4_i32, // SYS_write in("r0") fd, in("r1") buf, in("r2") count, lateout("r0") ret, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "svc #0", - in("r7") 6i32, // SYS_close + in("r7") 6_i32, // SYS_close in("r0") fd, lateout("r0") ret, options(nostack) @@ -64,12 +66,12 @@ pub(super) unsafe fn sys_close(fd: i32) -> i32 { } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "svc #0", - in("r7") 122i32, // SYS_newuname + in("r7") 122_i32, // SYS_newuname in("r0") buf, lateout("r0") ret, options(nostack) @@ -78,14 +80,14 @@ pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "svc #0", - in("r7") 266i32, // SYS_statfs64 + in("r7") 266_i32, // SYS_statfs64 in("r0") path, - in("r1") core::mem::size_of::(), + in("r1") size_of::(), in("r2") buf, lateout("r0") ret, options(nostack) @@ -94,10 +96,10 @@ pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "svc #0", in("r7") 116_i32, // __NR_sysinfo in("r0") info, @@ -108,16 +110,16 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "svc #0", - in("r7") 242i32, // __NR_sched_getaffinity + in("r7") 242_i32, // __NR_sched_getaffinity in("r0") pid, in("r1") mask_size, in("r2") mask, @@ -128,11 +130,11 @@ pub(super) unsafe fn sys_sched_getaffinity( } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "svc #0", - in("r7") 1i32, // SYS_exit + in("r7") 1_i32, // SYS_exit in("r0") code, options(noreturn, nostack) ); diff --git a/crates/asm/src/darwin.rs b/crates/asm/src/darwin.rs index 4c15518..be4c6ca 100644 --- a/crates/asm/src/darwin.rs +++ b/crates/asm/src/darwin.rs @@ -1,8 +1,9 @@ //! macOS does not support a stable raw-syscall ABI the way Linux does, cannot //! be linked statically, and exposes none of the `/proc`, `/sys`, or -//! `/etc/os-release` interfaces the Linux path relies on. So instead of -//! handwritten `svc #0` traps, this module calls into `libSystem` (which is -//! always linked on macOS) via plain FFI: +//! `/etc/os-release` interfaces the Linux path relies on. +//! +//! So instead of handwritten `svc #0` traps, this module calls into `libSystem` +//! (which is always linked on macOS) via plain FFI: //! //! * file/IO + exit -> `open`/`read`/`write`/`close`/`_exit` //! * `uname(3)` -> kernel name/release/machine @@ -19,7 +20,7 @@ use core::{ ptr, }; -use super::{StatfsBuf, SysInfo, UtsNameBuf}; +use super::{StatfsBuf, UtsNameBuf}; #[link(name = "System", kind = "dylib")] unsafe extern "C" { @@ -47,7 +48,7 @@ unsafe extern "C" { newp: *const c_void, newlen: usize, ) -> c_int; - fn gettimeofday(tp: *mut Timeval, tzp: *mut c_void) -> c_int; + fn gettimeofday(timeval: *mut Timeval, tzp: *mut c_void) -> c_int; // Mach host interfaces (live in libsystem_kernel, part of libSystem). fn mach_host_self() -> u32; // mach_port_t @@ -59,48 +60,31 @@ unsafe extern "C" { ) -> c_int; } -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub(crate) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { open(path.cast::(), flags) } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub(crate) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { read(fd, buf.cast::(), count) } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub(crate) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { write(fd, buf.cast::(), count) } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub(crate) unsafe fn sys_close(fd: i32) -> i32 { unsafe { close(fd) } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub(crate) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { uname(buf) } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub(crate) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { statfs(path.cast::(), buf) } } -/// macOS has no `sysinfo(2)`; uptime comes from [`macos_uptime_secs`] instead. -/// This stub exists only so the generic wrapper in `lib.rs` keeps compiling. -pub(super) unsafe fn sys_sysinfo(_info: *mut SysInfo) -> i64 { - -1 -} - -/// macOS has no `sched_getaffinity(2)`; core counts come from `sysctl` -/// (`hw.logicalcpu` / `hw.physicalcpu`). This stub keeps the generic wrapper -/// compiling. -pub(super) unsafe fn sys_sched_getaffinity( - _pid: i32, - _mask_size: usize, - _mask: *mut u8, -) -> i32 { - -1 -} - -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub(crate) unsafe fn sys_exit(code: i32) -> ! { unsafe { _exit(code) } } @@ -108,19 +92,19 @@ pub(super) unsafe fn sys_exit(code: i32) -> ! { /// NUL-terminated byte string (e.g. `b"machdep.cpu.brand_string\0"`). /// /// Returns the number of bytes written, excluding the trailing NUL. -#[must_use] +#[must_use = "the length says how much of `out` was filled"] pub fn macos_sysctl_str(name: &[u8], out: &mut [u8]) -> Option { let mut len = out.len(); let ret = unsafe { sysctlbyname( name.as_ptr().cast::(), out.as_mut_ptr().cast::(), - &mut len, + &raw mut len, ptr::null(), 0, ) }; - if ret != 0 { + if ret != 0_i32 { return None; } // `len` includes the terminating NUL on success. @@ -128,44 +112,36 @@ pub fn macos_sysctl_str(name: &[u8], out: &mut [u8]) -> Option { } /// Read a 32-bit integer sysctl by name (e.g. `b"hw.logicalcpu\0"`). -#[must_use] +#[must_use = "this only queries the kernel"] pub fn macos_sysctl_u32(name: &[u8]) -> Option { - let mut val: u32 = 0; + let mut val = 0_u32; let mut len = size_of::(); let ret = unsafe { sysctlbyname( name.as_ptr().cast::(), ptr::from_mut(&mut val).cast::(), - &mut len, + &raw mut len, ptr::null(), 0, ) }; - if ret == 0 && len == size_of::() { - Some(val) - } else { - None - } + (ret == 0_i32 && len == size_of::()).then_some(val) } /// Read a 64-bit integer sysctl by name (e.g. `b"hw.memsize\0"`). fn macos_sysctl_u64(name: &[u8]) -> Option { - let mut val: u64 = 0; + let mut val = 0_u64; let mut len = size_of::(); let ret = unsafe { sysctlbyname( name.as_ptr().cast::(), ptr::from_mut(&mut val).cast::(), - &mut len, + &raw mut len, ptr::null(), 0, ) }; - if ret == 0 && len == size_of::() { - Some(val) - } else { - None - } + (ret == 0_i32 && len == size_of::()).then_some(val) } const HOST_VM_INFO64: c_int = 4; @@ -175,7 +151,6 @@ const HOST_VM_INFO64: c_int = 4; /// `host_statistics64` matches the kernel's expectation exactly (38 ints). #[repr(C)] #[derive(Default)] -#[allow(dead_code, reason = "most fields exist only to fix the struct layout")] struct VmStatistics64 { free_count: u32, active_count: u32, @@ -209,30 +184,31 @@ struct VmStatistics64 { /// Used" as `(active + wired + compressed) * page_size`; inactive and free /// pages are treated as available. This is an approximation and the exact /// formula can be tuned against real hardware. -#[must_use] +#[must_use = "this only queries the kernel"] pub fn macos_meminfo() -> Option<(u64, u64)> { let total = macos_sysctl_u64(b"hw.memsize\0")?; // Apple Silicon uses 16 KiB pages; fall back to that if the sysctl is absent. - let page = u64::from(macos_sysctl_u32(b"hw.pagesize\0").unwrap_or(16384)); + let page = u64::from(macos_sysctl_u32(b"hw.pagesize\0").unwrap_or(0x4000)); - let mut vm = VmStatistics64::default(); - let mut count = (size_of::() / size_of::()) as u32; - let kr = unsafe { + let mut vm_stats = VmStatistics64::default(); + let mut count = + u32::try_from(size_of::() / size_of::()).ok()?; + let ret = unsafe { host_statistics64( mach_host_self(), HOST_VM_INFO64, - ptr::from_mut(&mut vm).cast::(), - &mut count, + ptr::from_mut(&mut vm_stats).cast::(), + &raw mut count, ) }; - if kr != 0 { + if ret != 0_i32 { // Mach call failed; report total with unknown usage rather than erroring. return Some((0, total)); } - let used = (u64::from(vm.active_count) - + u64::from(vm.wire_count) - + u64::from(vm.compressor_page_count)) + let used = (u64::from(vm_stats.active_count) + + u64::from(vm_stats.wire_count) + + u64::from(vm_stats.compressor_page_count)) * page; Some((used.min(total), total)) } @@ -240,10 +216,6 @@ pub fn macos_meminfo() -> Option<(u64, u64)> { /// `struct timeval` (`time_t` is 64-bit, `suseconds_t` is 32-bit on macOS). #[repr(C)] #[derive(Default)] -#[allow( - dead_code, - reason = "tv_usec/_pad exist only to fix the struct layout" -)] struct Timeval { tv_sec: i64, tv_usec: i32, @@ -254,7 +226,7 @@ const CTL_KERN: c_int = 1; const KERN_BOOTTIME: c_int = 21; /// Returns the system uptime in seconds (`now - kern.boottime`). -#[must_use] +#[must_use = "this only queries the kernel"] pub fn macos_uptime_secs() -> Option { let mib = [CTL_KERN, KERN_BOOTTIME]; let mut boot = Timeval::default(); @@ -262,19 +234,19 @@ pub fn macos_uptime_secs() -> Option { let ret = unsafe { sysctl( mib.as_ptr(), - mib.len() as u32, + u32::try_from(mib.len()).ok()?, ptr::from_mut(&mut boot).cast::(), - &mut len, + &raw mut len, ptr::null(), 0, ) }; - if ret != 0 { + if ret != 0_i32 { return None; } let mut now = Timeval::default(); - if unsafe { gettimeofday(&mut now, ptr::null_mut()) } != 0 { + if unsafe { gettimeofday(&raw mut now, ptr::null_mut()) } != 0_i32 { return None; } diff --git a/crates/asm/src/lib.rs b/crates/asm/src/lib.rs index 3b27962..9ab1868 100644 --- a/crates/asm/src/lib.rs +++ b/crates/asm/src/lib.rs @@ -20,13 +20,14 @@ feature(asm_experimental_arch) )] -#[cfg(not(target_os = "macos"))] use core::ffi::c_void; +#[cfg(not(target_os = "macos"))] +use core::ffi::{c_char, c_void}; // Per-arch syscall implementations live in their own module files. // macOS is matched first; there `target_arch` is `aarch64`, but the // implementation is libSystem-backed rather than raw `svc` traps. core::cfg_select! { - all(target_os = "macos", target_arch = "aarch64") => { #[path = "darwin.rs" ] mod arch; } + all(target_os = "macos", target_arch = "aarch64") => { pub mod darwin; use darwin as arch; } target_os = "macos" => { compile_error!("microfetch on macOS supports aarch64 (Apple Silicon) only"); } target_arch = "x86_64" => { #[path = "x86_64.rs" ] mod arch; } target_arch = "aarch64" => { #[path = "aarch64.rs" ] mod arch; } @@ -45,15 +46,6 @@ core::cfg_select! { _ => { compile_error!("Unsupported architecture"); } } -/// macOS-only helpers backed by `sysctl`/Mach (see `darwin.rs`). -#[cfg(target_os = "macos")] -pub use arch::{ - macos_meminfo, - macos_sysctl_str, - macos_sysctl_u32, - macos_uptime_secs, -}; - #[cfg(not(target_os = "macos"))] const WORD: usize = size_of::(); @@ -71,45 +63,51 @@ const UNALIGNED_WORDS: bool = cfg!(any( target_arch = "loongarch64", )); -/// Copies `n` bytes from `src` to `dest`. +/// Copies `len` bytes from `src` to `dest`. /// /// # Safety /// /// `dest` and `src` must be valid pointers to non-overlapping regions of -/// memory of at least `n` bytes. +/// memory of at least `len` bytes. // On macOS these symbols are supplied by libSystem; defining our own would // clash at link time, so the freestanding implementations are Linux-only. #[cfg(not(target_os = "macos"))] #[unsafe(no_mangle)] -#[allow(clippy::cast_ptr_alignment)] +#[expect( + clippy::cast_ptr_alignment, + reason = "word accesses are either unaligned or follow an alignment prologue" +)] pub unsafe extern "C" fn memcpy( dest: *mut c_void, src: *const c_void, - n: usize, + len: usize, ) -> *mut c_void { let dest_bytes = dest.cast::(); let src_bytes = src.cast::(); - let mut i = 0; + let mut offset = 0; unsafe { if UNALIGNED_WORDS { - while n - i >= WORD { - let word = src_bytes.add(i).cast::().read_unaligned(); - dest_bytes.add(i).cast::().write_unaligned(word); - i += WORD; + while len - offset >= WORD { + let word = src_bytes.add(offset).cast::().read_unaligned(); + dest_bytes.add(offset).cast::().write_unaligned(word); + offset += WORD; } - } else if dest_bytes as usize % WORD == src_bytes as usize % WORD { - while i < n && !(dest_bytes.add(i) as usize).is_multiple_of(WORD) { - *dest_bytes.add(i) = *src_bytes.add(i); - i += 1; + } + if !UNALIGNED_WORDS && dest_bytes.addr() % WORD == src_bytes.addr() % WORD { + while offset < len && !dest_bytes.add(offset).addr().is_multiple_of(WORD) + { + *dest_bytes.add(offset) = *src_bytes.add(offset); + offset += 1; } - while n - i >= WORD { - *dest_bytes.add(i).cast::() = *src_bytes.add(i).cast::(); - i += WORD; + while len - offset >= WORD { + *dest_bytes.add(offset).cast::() = + *src_bytes.add(offset).cast::(); + offset += WORD; } } - while i < n { - *dest_bytes.add(i) = *src_bytes.add(i); - i += 1; + while offset < len { + *dest_bytes.add(offset) = *src_bytes.add(offset); + offset += 1; } } dest @@ -119,64 +117,67 @@ pub unsafe extern "C" fn memcpy( /// /// # Safety /// -/// `s` must be a valid pointer to memory of at least `n` bytes. -/// The value in `c` is treated as unsigned (lower 8 bits used). +/// `dest` must be a valid pointer to memory of at least `len` bytes. +/// The value in `fill` is treated as unsigned (lower 8 bits used). #[cfg(not(target_os = "macos"))] #[unsafe(no_mangle)] -#[allow(clippy::cast_ptr_alignment)] +#[expect( + clippy::cast_ptr_alignment, + reason = "word accesses are either unaligned or follow an alignment prologue" +)] pub unsafe extern "C" fn memset( - s: *mut c_void, - c: i32, - n: usize, + dest: *mut c_void, + fill: i32, + len: usize, ) -> *mut c_void { - let bytes = s.cast::(); - let value = c.to_le_bytes()[0]; - let mut i = 0; + let bytes = dest.cast::(); + let value = u8::try_from(fill & 0xFF_i32).unwrap_or(0); + let mut offset = 0; unsafe { if UNALIGNED_WORDS { - let word = usize::from_ne_bytes([value; WORD]); - while n - i >= WORD { - bytes.add(i).cast::().write_unaligned(word); - i += WORD; + let word = usize::MAX / 0xFF * usize::from(value); + while len - offset >= WORD { + bytes.add(offset).cast::().write_unaligned(word); + offset += WORD; } } else { - while i < n && !(bytes.add(i) as usize).is_multiple_of(WORD) { - *bytes.add(i) = value; - i += 1; + while offset < len && !bytes.add(offset).addr().is_multiple_of(WORD) { + *bytes.add(offset) = value; + offset += 1; } - let word = usize::from_ne_bytes([value; WORD]); - while n - i >= WORD { - *bytes.add(i).cast::() = word; - i += WORD; + let word = usize::MAX / 0xFF * usize::from(value); + while len - offset >= WORD { + *bytes.add(offset).cast::() = word; + offset += WORD; } } - while i < n { - *bytes.add(i) = value; - i += 1; + while offset < len { + *bytes.add(offset) = value; + offset += 1; } } - s + dest } /// Compares two byte sequences. /// /// # Safety /// -/// `s1` and `s2` must be valid pointers to memory of at least `n` bytes. +/// `left` and `right` must be valid pointers to memory of at least `len` bytes. #[cfg(not(target_os = "macos"))] #[unsafe(no_mangle)] pub unsafe extern "C" fn bcmp( - s1: *const c_void, - s2: *const c_void, - n: usize, + left: *const c_void, + right: *const c_void, + len: usize, ) -> i32 { - let bytes1 = s1.cast::(); - let bytes2 = s2.cast::(); - for i in 0..n { - let a = unsafe { *bytes1.add(i) }; - let b = unsafe { *bytes2.add(i) }; - if a != b { - return i32::from(a) - i32::from(b); + let bytes1 = left.cast::(); + let bytes2 = right.cast::(); + for offset in 0..len { + let left_byte = unsafe { *bytes1.add(offset) }; + let right_byte = unsafe { *bytes2.add(offset) }; + if left_byte != right_byte { + return i32::from(left_byte) - i32::from(right_byte); } } 0 @@ -186,27 +187,27 @@ pub unsafe extern "C" fn bcmp( /// /// # Safety /// -/// `s1` and `s2` must be valid pointers to memory of at least `n` bytes. +/// `left` and `right` must be valid pointers to memory of at least `len` bytes. #[cfg(not(target_os = "macos"))] #[unsafe(no_mangle)] pub unsafe extern "C" fn memcmp( - s1: *const c_void, - s2: *const c_void, - n: usize, + left: *const c_void, + right: *const c_void, + len: usize, ) -> i32 { - unsafe { bcmp(s1, s2, n) } + unsafe { bcmp(left, right, len) } } /// Calculates the length of a null-terminated string. /// /// # Safety /// -/// `s` must be a valid pointer to a null-terminated string. +/// `cstr` must be a valid pointer to a null-terminated string. #[cfg(not(target_os = "macos"))] #[unsafe(no_mangle)] -pub const unsafe extern "C" fn strlen(s: *const i8) -> usize { +pub const unsafe extern "C" fn strlen(cstr: *const c_char) -> usize { let mut len = 0; - while unsafe { *s.add(len) } != 0 { + while unsafe { *cstr.add(len) } != 0 { len += 1; } len @@ -253,7 +254,7 @@ pub unsafe extern "C" fn entry_rust(stack: *const usize) -> i32 { let argc = unsafe { *stack }; let argv = unsafe { stack.add(1).cast::<*const u8>() }; - // SAFETY: argc is unlikely to exceed i32::MAX on real systems + // argc is unlikely to exceed i32::MAX on real systems let argc_i32 = i32::try_from(argc).unwrap_or(i32::MAX); // Call the main function (defined by the binary crate) @@ -268,11 +269,11 @@ unsafe extern "C" { fn main(argc: i32, argv: *const *const u8) -> i32; } -/// Direct syscall to open a file +/// Direct syscall to open a file. /// /// # Returns /// -/// File descriptor or -1 on error +/// File descriptor or -1 on error. /// /// # Safety /// @@ -281,16 +282,16 @@ unsafe extern "C" { /// - `path` points to a valid null-terminated C string /// - The pointer remains valid for the duration of the syscall #[inline] -#[must_use] +#[must_use = "the descriptor must be checked and closed"] pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { arch::sys_open(path, flags) } } -/// Direct syscall to read from a file descriptor +/// Direct syscall to read from a file descriptor. /// /// # Returns /// -/// Number of bytes read or -1 on error +/// Number of bytes read or -1 on error. /// /// # Safety /// @@ -303,11 +304,11 @@ pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { arch::sys_read(fd, buf, count) } } -/// Direct syscall to write to a file descriptor +/// Direct syscall to write to a file descriptor. /// /// # Returns /// -/// Number of bytes written or -1 on error +/// Number of bytes written or -1 on error. /// /// # Safety /// @@ -316,18 +317,18 @@ pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { /// - `buf` points to a valid readable buffer of at least `count` bytes /// - `fd` is a valid open file descriptor #[inline] -#[must_use] +#[must_use = "a short or failed write goes unnoticed otherwise"] pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { arch::sys_write(fd, buf, count) } } -/// Direct syscall to close a file descriptor +/// Direct syscall to close a file descriptor. /// /// # Safety /// -/// The caller must ensure that `fd` is a valid open file descriptor +/// The caller must ensure that `fd` is a valid open file descriptor. #[inline] -#[must_use] +#[must_use = "close can report a deferred I/O error"] pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { arch::sys_close(fd) } } @@ -338,7 +339,6 @@ pub unsafe fn sys_close(fd: i32) -> i32 { /// machine. The `domainname` field (GNU extension, `[i8; 65]`) follows but is /// not used, nor any useful to us here. #[repr(C)] -#[allow(dead_code)] #[cfg(not(target_os = "macos"))] pub struct UtsNameBuf { pub sysname: [i8; 65], @@ -362,17 +362,16 @@ pub struct UtsNameBuf { pub machine: [i8; 256], } -/// Direct `uname(2)` syscall +/// Direct `uname(2)` syscall. /// /// # Returns /// -/// 0 on success, negative on error +/// 0 on success, negative on error. /// /// # Safety /// /// The caller must ensure that `buf` points to a valid `UtsNameBuf`. #[inline] -#[allow(dead_code)] pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { arch::sys_uname(buf) } } @@ -381,7 +380,7 @@ pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { /// /// Linux ABI (`x86_64` and `aarch64`): the fields we use are at the same /// offsets on both architectures. Only the fields needed for disk usage are -/// declared; the remainder of the 120-byte struct is covered by `_pad`. +/// declared; the remainder of the 120-byte struct is covered by `spare`. #[repr(C)] #[cfg(not(any( target_os = "macos", @@ -407,13 +406,32 @@ pub struct StatfsBuf { pub f_frsize: i64, pub f_flags: i64, - #[allow(clippy::pub_underscore_fields, reason = "This is not a public API")] - pub _pad: [i64; 4], + pub spare: [i64; 4], +} + +#[cfg(not(any( + target_os = "macos", + target_arch = "s390x", + target_arch = "arm", + target_arch = "riscv32", + target_arch = "x86", + target_arch = "powerpc", + target_arch = "sparc", + target_arch = "mips64", + target_arch = "mips" +)))] +impl StatfsBuf { + #[must_use = "this only reads a field"] + pub const fn block_size(&self) -> u64 { + self.f_bsize.unsigned_abs() + } } /// macOS `struct statfs` (the 64-bit/`INODE64` ABI, which is the only one on -/// arm64). Only `f_bsize`, `f_blocks`, and `f_bavail` are read; the rest is -/// declared to give the struct its correct size and field offsets. +/// arm64). +/// +/// Only `f_bsize`, `f_blocks`, and `f_bavail` are read; the rest is declared +/// to give the struct its correct size and field offsets. #[repr(C)] #[cfg(target_os = "macos")] pub struct StatfsBuf { @@ -436,6 +454,14 @@ pub struct StatfsBuf { pub f_reserved: [u32; 7], } +#[cfg(target_os = "macos")] +impl StatfsBuf { + #[must_use = "this only reads a field"] + pub fn block_size(&self) -> u64 { + u64::from(self.f_bsize) + } +} + /// on s390x `f_type` and `f_bsize` are 32-bit. #[repr(C)] #[cfg(target_arch = "s390x")] @@ -452,12 +478,19 @@ pub struct StatfsBuf { pub f_frsize: u32, pub f_flags: u32, - #[allow(clippy::pub_underscore_fields, reason = "This is not a public API")] - pub _pad: [u32; 5], + pub spare: [u32; 5], +} + +#[cfg(target_arch = "s390x")] +impl StatfsBuf { + #[must_use = "this only reads a field"] + pub fn block_size(&self) -> u64 { + u64::from(self.f_bsize) + } } /// on armv7 `statfs64(2)` has 32-bit word fields; see -/// https://github.com/torvalds/linux/blob/v6.19/include/uapi/asm-generic/statfs.h +/// . #[repr(C)] #[cfg(any( target_arch = "arm", @@ -479,19 +512,32 @@ pub struct StatfsBuf { pub f_frsize: u32, pub f_flags: u32, - #[allow(clippy::pub_underscore_fields, reason = "This is not a public API")] - pub _pad: [u32; 4], + pub spare: [u32; 4], +} + +#[cfg(any( + target_arch = "arm", + target_arch = "riscv32", + target_arch = "x86", + target_arch = "powerpc", + target_arch = "sparc" +))] +impl StatfsBuf { + #[must_use = "this only reads a field"] + pub fn block_size(&self) -> u64 { + u64::from(self.f_bsize) + } } /// mips (O32) uses `compat_statfs64`, same reordering with 32-bit words; see -/// https://github.com/torvalds/linux/blob/v6.19/arch/mips/include/uapi/asm/statfs.h +/// . #[repr(C)] #[cfg(target_arch = "mips")] pub struct StatfsBuf { pub f_type: u32, pub f_bsize: u32, pub f_frsize: u32, - _pad: u32, + pub pad: u32, pub f_blocks: u64, pub f_bfree: u64, pub f_files: u64, @@ -501,12 +547,19 @@ pub struct StatfsBuf { pub f_namelen: u32, pub f_flags: u32, - #[allow(clippy::pub_underscore_fields, reason = "This is not a public API")] - pub _pad2: [u32; 5], + pub spare: [u32; 5], +} + +#[cfg(target_arch = "mips")] +impl StatfsBuf { + #[must_use = "this only reads a field"] + pub fn block_size(&self) -> u64 { + u64::from(self.f_bsize) + } } /// mips reorders fields; see -/// https://github.com/torvalds/linux/blob/v6.19/arch/mips/include/uapi/asm/statfs.h +/// . #[repr(C)] #[cfg(target_arch = "mips64")] pub struct StatfsBuf { @@ -522,15 +575,22 @@ pub struct StatfsBuf { pub f_namelen: i64, pub f_flags: i64, - #[allow(clippy::pub_underscore_fields, reason = "This is not a public API")] - pub _pad: [i64; 5], + pub spare: [i64; 5], } -/// Direct `statfs(2)` syscall +#[cfg(target_arch = "mips64")] +impl StatfsBuf { + #[must_use = "this only reads a field"] + pub const fn block_size(&self) -> u64 { + self.f_bsize.unsigned_abs() + } +} + +/// Direct `statfs(2)` syscall. /// /// # Returns /// -/// 0 on success, negative errno on error +/// 0 on success, negative errno on error. /// /// # Safety /// @@ -561,7 +621,7 @@ pub fn read_file_fast(path: &str, buffer: &mut [u8]) -> Result { return Err(-22); // EINVAL } - let mut path_buf = [0u8; 256]; + let mut path_buf = [0_u8; 256]; path_buf[..path_bytes.len()].copy_from_slice(path_bytes); // XXX: Already zero-terminated since array is initialized to zeros @@ -572,17 +632,12 @@ pub fn read_file_fast(path: &str, buffer: &mut [u8]) -> Result { } let bytes_read = sys_read(fd, buffer.as_mut_ptr(), buffer.len()); - let _ = sys_close(fd); - - if bytes_read < 0 { - #[allow(clippy::cast_possible_truncation)] - return Err(bytes_read as i32); - } + _ = sys_close(fd); - #[allow(clippy::cast_sign_loss)] - { - Ok(bytes_read as usize) - } + let Ok(len) = usize::try_from(bytes_read) else { + return Err(i32::try_from(bytes_read).unwrap_or(i32::MIN)); + }; + Ok(len) } } @@ -596,6 +651,7 @@ pub fn read_file_fast(path: &str, buffer: &mut [u8]) -> Result { /// `mem_unit` ends at offset 108, then 4 bytes of implicit padding to 112. #[repr(C)] #[cfg(not(any( + target_os = "macos", target_arch = "arm", target_arch = "riscv32", target_arch = "x86", @@ -613,8 +669,8 @@ pub struct SysInfo { pub totalswap: u64, pub freeswap: u64, pub procs: u16, - _pad: u16, - _pad2: u32, /* alignment padding to reach 8-byte boundary for + pub pad: u16, + pub pad2: u32, /* alignment padding to reach 8-byte boundary for * totalhigh */ pub totalhigh: u64, pub freehigh: u64, @@ -624,7 +680,7 @@ pub struct SysInfo { } /// on armv7 `__kernel_long_t` is 4 bytes; see -/// https://github.com/torvalds/linux/blob/v6.19/include/uapi/linux/sysinfo.h +/// . #[repr(C)] #[cfg(any( target_arch = "arm", @@ -644,29 +700,29 @@ pub struct SysInfo { pub totalswap: u32, pub freeswap: u32, pub procs: u16, - _pad: u16, + pub pad: u16, pub totalhigh: u32, pub freehigh: u32, pub mem_unit: u32, - #[allow(clippy::pub_underscore_fields, reason = "This is not a public API")] - pub _f: [u8; 8], + pub spare: [u8; 8], } -/// Direct `sysinfo(2)` syscall +/// Direct `sysinfo(2)` syscall. /// /// # Returns /// -/// 0 on success, negative errno on error +/// 0 on success, negative errno on error. /// /// # Safety /// /// The caller must ensure that `info` points to a valid `SysInfo` buffer. +#[cfg(not(target_os = "macos"))] #[inline] pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { arch::sys_sysinfo(info) } } -/// Direct `sched_getaffinity(2)` syscall +/// Direct `sched_getaffinity(2)` syscall. /// /// # Returns /// @@ -677,6 +733,7 @@ pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { /// /// The caller must ensure that `mask` points to a buffer of at least /// `mask_size` bytes. +#[cfg(not(target_os = "macos"))] #[inline] pub unsafe fn sys_sched_getaffinity( pid: i32, @@ -686,7 +743,7 @@ pub unsafe fn sys_sched_getaffinity( unsafe { arch::sys_sched_getaffinity(pid, mask_size, mask) } } -/// Direct syscall to exit the process +/// Direct syscall to exit the process. /// /// # Safety /// @@ -698,31 +755,28 @@ pub unsafe fn sys_exit(code: i32) -> ! { // The freestanding memory symbols exist everywhere but macOS, where // libSystem supplies them instead. -#[cfg(all(test, not(target_os = "macos")))] +#[cfg(test)] +#[cfg(not(target_os = "macos"))] mod tests { use super::*; #[test] fn runtime_memory_symbols_match_c_semantics() { - let src = [1u8, 2, 3, 4]; - let mut dest = [0u8; 4]; + let src = [1_u8, 2, 3, 4]; + let mut dest = [0_u8; 4]; - unsafe { - memcpy(dest.as_mut_ptr().cast(), src.as_ptr().cast(), src.len()); - } + unsafe { memcpy(dest.as_mut_ptr().cast(), src.as_ptr().cast(), src.len()) }; assert_eq!(dest, src); assert_eq!( unsafe { memcmp(dest.as_ptr().cast(), src.as_ptr().cast(), 4) }, - 0 + 0_i32 ); - unsafe { - memset(dest.as_mut_ptr().cast(), -1, dest.len()); - } + unsafe { memset(dest.as_mut_ptr().cast(), -1, dest.len()) }; assert_eq!(dest, [u8::MAX; 4]); assert_ne!( unsafe { bcmp(dest.as_ptr().cast(), src.as_ptr().cast(), 4) }, - 0 + 0_i32 ); } diff --git a/crates/asm/src/loongarch64.rs b/crates/asm/src/loongarch64.rs index d5ab5ac..2475afa 100644 --- a/crates/asm/src/loongarch64.rs +++ b/crates/asm/src/loongarch64.rs @@ -1,121 +1,105 @@ //! Syscall implementations for `loongarch64`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { - let fd: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall 0", - in("$a7") 56i64, // SYS_openat - in("$a0") -100i32, // AT_FDCWD + in("$a7") 56_i64, // SYS_openat + in("$a0") -100_i32, // AT_FDCWD in("$a1") path, in("$a2") flags, - in("$a3") 0i32, // mode - lateout("$a0") fd, + in("$a3") 0_i32, // mode + lateout("$a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - fd as i32 - } + ret } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "syscall 0", - in("$a7") 63i64, // SYS_read + in("$a7") 63_i64, // SYS_read in("$a0") fd, in("$a1") buf, in("$a2") count, lateout("$a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "syscall 0", - in("$a7") 64i64, // SYS_write + in("$a7") 64_i64, // SYS_write in("$a0") fd, in("$a1") buf, in("$a2") count, lateout("$a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall 0", - in("$a7") 57i64, // SYS_close + in("$a7") 57_i64, // SYS_close in("$a0") fd, lateout("$a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall 0", - in("$a7") 160i64, // SYS_uname + in("$a7") 160_i64, // SYS_uname in("$a0") buf, lateout("$a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall 0", - in("$a7") 43i64, // SYS_statfs + in("$a7") 43_i64, // SYS_statfs in("$a0") path, in("$a1") buf, lateout("$a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i64; - core::arch::asm!( + asm!( "syscall 0", in("$a7") 179_i64, // __NR_sysinfo in("$a0") info, @@ -126,34 +110,31 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall 0", - in("$a7") 123i64, // __NR_sched_getaffinity + in("$a7") 123_i64, // __NR_sched_getaffinity in("$a0") pid, in("$a1") mask_size, in("$a2") mask, lateout("$a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "syscall 0", - in("$a7") 93i64, // SYS_exit + in("$a7") 93_i64, // SYS_exit in("$a0") code, options(noreturn, nostack) ); diff --git a/crates/asm/src/mips.rs b/crates/asm/src/mips.rs index c5adf17..f1fda08 100644 --- a/crates/asm/src/mips.rs +++ b/crates/asm/src/mips.rs @@ -1,20 +1,22 @@ //! Syscall implementations for `mips`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "syscall", "beqz $7, 1f", "nop", "subu $2, $0, $2", "1:", - inlateout("$2") 4000i32 + 5 => ret, // SYS_open + inlateout("$2") 4000_i32 + 5 => ret, // SYS_open in("$4") path, in("$5") flags, - in("$6") 0i32, // mode + in("$6") 0_i32, // mode lateout("$7") _, lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _, lateout("$12") _, lateout("$13") _, lateout("$14") _, lateout("$15") _, @@ -25,16 +27,16 @@ pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "syscall", "beqz $7, 1f", "nop", "subu $2, $0, $2", "1:", - inlateout("$2") 4000i32 + 3 => ret, // SYS_read + inlateout("$2") 4000_i32 + 3 => ret, // SYS_read in("$4") fd, in("$5") buf, in("$6") count, @@ -44,20 +46,20 @@ pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { lateout("$24") _, lateout("$25") _, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "syscall", "beqz $7, 1f", "nop", "subu $2, $0, $2", "1:", - inlateout("$2") 4000i32 + 4 => ret, // SYS_write + inlateout("$2") 4000_i32 + 4 => ret, // SYS_write in("$4") fd, in("$5") buf, in("$6") count, @@ -67,20 +69,20 @@ pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { lateout("$24") _, lateout("$25") _, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "syscall", "beqz $7, 1f", "nop", "subu $2, $0, $2", "1:", - inlateout("$2") 4000i32 + 6 => ret, // SYS_close + inlateout("$2") 4000_i32 + 6 => ret, // SYS_close in("$4") fd, lateout("$7") _, lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _, @@ -92,16 +94,16 @@ pub(super) unsafe fn sys_close(fd: i32) -> i32 { } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "syscall", "beqz $7, 1f", "nop", "subu $2, $0, $2", "1:", - inlateout("$2") 4000i32 + 122 => ret, // SYS_newuname + inlateout("$2") 4000_i32 + 122 => ret, // SYS_newuname in("$4") buf, lateout("$7") _, lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _, @@ -113,18 +115,18 @@ pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "syscall", "beqz $7, 1f", "nop", "subu $2, $0, $2", "1:", - inlateout("$2") 4000i32 + 255 => ret, // SYS_statfs64 + inlateout("$2") 4000_i32 + 255 => ret, // SYS_statfs64 in("$4") path, - in("$5") core::mem::size_of::(), + in("$5") size_of::(), in("$6") buf, lateout("$7") _, lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _, @@ -136,10 +138,10 @@ pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "syscall", "beqz $7, 1f", "nop", @@ -157,20 +159,20 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "syscall", "beqz $7, 1f", "nop", "subu $2, $0, $2", "1:", - inlateout("$2") 4000i32 + 240 => ret, // __NR_sched_getaffinity + inlateout("$2") 4000_i32 + 240 => ret, // __NR_sched_getaffinity in("$4") pid, in("$5") mask_size, in("$6") mask, @@ -184,11 +186,11 @@ pub(super) unsafe fn sys_sched_getaffinity( } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "syscall", - in("$2") 4000i32 + 1, // SYS_exit + in("$2") 4000_i32 + 1, // SYS_exit in("$4") code, options(noreturn, nostack) ); diff --git a/crates/asm/src/mips64.rs b/crates/asm/src/mips64.rs index 9127a1e..12bd511 100644 --- a/crates/asm/src/mips64.rs +++ b/crates/asm/src/mips64.rs @@ -1,43 +1,44 @@ //! Syscall implementations for `mips64`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall", "beqz $7, 1f", "nop", "dsubu $2, $0, $2", "1:", - inlateout("$2") 5000i64 + 2 => ret, // SYS_open + in("$2") 5000_i64 + 2, // SYS_open + lateout("$2") ret, in("$4") path, in("$5") flags, - in("$6") 0i32, // mode + in("$6") 0_i32, // mode lateout("$7") _, lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _, lateout("$12") _, lateout("$13") _, lateout("$14") _, lateout("$15") _, lateout("$24") _, lateout("$25") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "syscall", "beqz $7, 1f", "nop", "dsubu $2, $0, $2", "1:", - inlateout("$2") 5000i64 + 0 => ret, // SYS_read + in("$2") 5000_i64 + 0, // SYS_read + lateout("$2") ret, in("$4") fd, in("$5") buf, in("$6") count, @@ -47,20 +48,21 @@ pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { lateout("$24") _, lateout("$25") _, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "syscall", "beqz $7, 1f", "nop", "dsubu $2, $0, $2", "1:", - inlateout("$2") 5000i64 + 1 => ret, // SYS_write + in("$2") 5000_i64 + 1, // SYS_write + lateout("$2") ret, in("$4") fd, in("$5") buf, in("$6") count, @@ -70,20 +72,21 @@ pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { lateout("$24") _, lateout("$25") _, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall", "beqz $7, 1f", "nop", "dsubu $2, $0, $2", "1:", - inlateout("$2") 5000i64 + 3 => ret, // SYS_close + in("$2") 5000_i64 + 3, // SYS_close + lateout("$2") ret, in("$4") fd, lateout("$7") _, lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _, @@ -91,23 +94,21 @@ pub(super) unsafe fn sys_close(fd: i32) -> i32 { lateout("$24") _, lateout("$25") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall", "beqz $7, 1f", "nop", "dsubu $2, $0, $2", "1:", - inlateout("$2") 5000i64 + 61 => ret, // SYS_newuname + in("$2") 5000_i64 + 61, // SYS_newuname + lateout("$2") ret, in("$4") buf, lateout("$7") _, lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _, @@ -115,23 +116,21 @@ pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { lateout("$24") _, lateout("$25") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall", "beqz $7, 1f", "nop", "dsubu $2, $0, $2", "1:", - inlateout("$2") 5000i64 + 134 => ret, // SYS_statfs + in("$2") 5000_i64 + 134, // SYS_statfs + lateout("$2") ret, in("$4") path, in("$5") buf, lateout("$7") _, @@ -140,23 +139,21 @@ pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { lateout("$24") _, lateout("$25") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i64; - core::arch::asm!( + asm!( "syscall", "beqz $7, 1f", "nop", "dsubu $2, $0, $2", "1:", - inlateout("$2") 5000_i64 + 97 => ret, // SYS_sysinfo + in("$2") 5000_i64 + 97, // SYS_sysinfo + lateout("$2") ret, in("$4") info, lateout("$7") _, lateout("$8") _, lateout("$9") _, lateout("$10") _, lateout("$11") _, @@ -168,16 +165,17 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall", - inlateout("$2") 5000i64 + 196 => ret, // __NR_sched_getaffinity + in("$2") 5000_i64 + 196, // __NR_sched_getaffinity + lateout("$2") ret, in("$4") pid, in("$5") mask_size, in("$6") mask, @@ -187,18 +185,15 @@ pub(super) unsafe fn sys_sched_getaffinity( lateout("$24") _, lateout("$25") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "syscall", - in("$2") 5000i64 + 58, // SYS_exit + in("$2") 5000_i64 + 58, // SYS_exit in("$4") code, options(noreturn, nostack) ); diff --git a/crates/asm/src/powerpc.rs b/crates/asm/src/powerpc.rs index e2e7829..b1f9c5a 100644 --- a/crates/asm/src/powerpc.rs +++ b/crates/asm/src/powerpc.rs @@ -1,19 +1,21 @@ //! Syscall implementations for `powerpc`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 5i32 => _, // SYS_open + inlateout("r0") 5_i32 => _, // SYS_open inlateout("r3") path => ret, inlateout("r4") flags => _, - inlateout("r5") 0i32 => _, + inlateout("r5") 0_i32 => _, out("r6") _, out("r7") _, out("r8") _, out("r9") _, out("r10") _, out("r11") _, out("r12") _, out("cr0") _, @@ -23,15 +25,15 @@ pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 3i32 => _, // SYS_read + inlateout("r0") 3_i32 => _, // SYS_read inlateout("r3") fd => ret, inlateout("r4") buf => _, inlateout("r5") count => _, @@ -40,19 +42,19 @@ pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { out("cr0") _, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 4i32 => _, // SYS_write + inlateout("r0") 4_i32 => _, // SYS_write inlateout("r3") fd => ret, inlateout("r4") buf => _, inlateout("r5") count => _, @@ -61,19 +63,19 @@ pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { out("cr0") _, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 6i32 => _, // SYS_close + inlateout("r0") 6_i32 => _, // SYS_close inlateout("r3") fd => ret, out("r4") _, out("r5") _, out("r6") _, out("r7") _, out("r8") _, out("r9") _, out("r10") _, out("r11") _, out("r12") _, @@ -84,15 +86,15 @@ pub(super) unsafe fn sys_close(fd: i32) -> i32 { } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 122i32 => _, // SYS_newuname + inlateout("r0") 122_i32 => _, // SYS_newuname inlateout("r3") buf => ret, out("r4") _, out("r5") _, out("r6") _, out("r7") _, out("r8") _, out("r9") _, out("r10") _, out("r11") _, out("r12") _, @@ -103,17 +105,17 @@ pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 252i32 => _, // SYS_statfs64 + inlateout("r0") 252_i32 => _, // SYS_statfs64 inlateout("r3") path => ret, - inlateout("r4") core::mem::size_of::() => _, + inlateout("r4") size_of::() => _, inlateout("r5") buf => _, out("r6") _, out("r7") _, out("r8") _, out("r9") _, out("r10") _, out("r11") _, out("r12") _, @@ -124,10 +126,10 @@ pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "sc", "bns+ 2f", "neg 3, 3", @@ -143,19 +145,19 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 223i32 => _, // __NR_sched_getaffinity + inlateout("r0") 223_i32 => _, // __NR_sched_getaffinity inlateout("r3") pid => ret, inlateout("r4") mask_size => _, inlateout("r5") mask => _, @@ -168,9 +170,9 @@ pub(super) unsafe fn sys_sched_getaffinity( } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "li 0, 1", // SYS_exit "sc", in("r3") code, diff --git a/crates/asm/src/powerpc64.rs b/crates/asm/src/powerpc64.rs index 13e0b33..597bdf3 100644 --- a/crates/asm/src/powerpc64.rs +++ b/crates/asm/src/powerpc64.rs @@ -1,41 +1,42 @@ //! Syscall implementations for `powerpc64`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 5i64 => _, // SYS_open - inlateout("r3") path => ret, + inlateout("r0") 5_i64 => _, // SYS_open + in("r3") path, + lateout("r3") ret, inlateout("r4") flags => _, - inlateout("r5") 0i32 => _, // mode + inlateout("r5") 0_i32 => _, // mode out("r6") _, out("r7") _, out("r8") _, out("r9") _, out("r10") _, out("r11") _, out("r12") _, out("cr0") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 3i64 => _, // SYS_read - inlateout("r3") fd as i64 => ret, + inlateout("r0") 3_i64 => _, // SYS_read + in("r3") i64::from(fd), + lateout("r3") ret, inlateout("r4") buf => _, inlateout("r5") count => _, out("r6") _, out("r7") _, out("r8") _, @@ -43,23 +44,21 @@ pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { out("cr0") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 4i64 => _, // SYS_write - inlateout("r3") fd as i64 => ret, + inlateout("r0") 4_i64 => _, // SYS_write + in("r3") i64::from(fd), + lateout("r3") ret, inlateout("r4") buf => _, inlateout("r5") count => _, out("r6") _, out("r7") _, out("r8") _, @@ -67,90 +66,82 @@ pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { out("cr0") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 6i64 => _, // SYS_close - inlateout("r3") fd as i64 => ret, + inlateout("r0") 6_i64 => _, // SYS_close + in("r3") i64::from(fd), + lateout("r3") ret, out("r4") _, out("r5") _, out("r6") _, out("r7") _, out("r8") _, out("r9") _, out("r10") _, out("r11") _, out("r12") _, out("cr0") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 122i64 => _, // SYS_uname - inlateout("r3") buf => ret, + inlateout("r0") 122_i64 => _, // SYS_uname + in("r3") buf, + lateout("r3") ret, out("r4") _, out("r5") _, out("r6") _, out("r7") _, out("r8") _, out("r9") _, out("r10") _, out("r11") _, out("r12") _, out("cr0") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 99i64 => _, // SYS_statfs - inlateout("r3") path => ret, + inlateout("r0") 99_i64 => _, // SYS_statfs + in("r3") path, + lateout("r3") ret, inlateout("r4") buf => _, out("r5") _, out("r6") _, out("r7") _, out("r8") _, out("r9") _, out("r10") _, out("r11") _, out("r12") _, out("cr0") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i64; - core::arch::asm!( + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", inlateout("r0") 116_i64 => _, // __NR_sysinfo - inlateout("r3") info => ret, + in("r3") info, + lateout("r3") ret, out("r4") _, out("r5") _, out("r6") _, out("r7") _, out("r8") _, out("r9") _, out("r10") _, out("r11") _, out("r12") _, out("cr0") _, @@ -160,20 +151,21 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "sc", "bns+ 2f", "neg 3, 3", "2:", - inlateout("r0") 223i64 => _, // __NR_sched_getaffinity - inlateout("r3") pid as i64 => ret, + inlateout("r0") 223_i64 => _, // __NR_sched_getaffinity + in("r3") i64::from(pid), + lateout("r3") ret, inlateout("r4") mask_size => _, inlateout("r5") mask => _, out("r6") _, out("r7") _, out("r8") _, @@ -181,16 +173,13 @@ pub(super) unsafe fn sys_sched_getaffinity( out("cr0") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "li 0, 1", // SYS_exit "sc", in("r3") code, diff --git a/crates/asm/src/riscv32.rs b/crates/asm/src/riscv32.rs index 1e4b29a..b30e8ce 100644 --- a/crates/asm/src/riscv32.rs +++ b/crates/asm/src/riscv32.rs @@ -1,17 +1,19 @@ //! Syscall implementations for `riscv32`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "ecall", - in("a7") 56i32, // SYS_openat - in("a0") -100i32, // AT_FDCWD + in("a7") 56_i32, // SYS_openat + in("a0") -100_i32, // AT_FDCWD in("a1") path, in("a2") flags, - in("a3") 0i32, // mode + in("a3") 0_i32, // mode lateout("a0") ret, options(nostack) ); @@ -19,44 +21,44 @@ pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "ecall", - in("a7") 63i32, // SYS_read + in("a7") 63_i32, // SYS_read in("a0") fd, in("a1") buf, in("a2") count, lateout("a0") ret, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "ecall", - in("a7") 64i32, // SYS_write + in("a7") 64_i32, // SYS_write in("a0") fd, in("a1") buf, in("a2") count, lateout("a0") ret, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "ecall", - in("a7") 57i32, // SYS_close + in("a7") 57_i32, // SYS_close in("a0") fd, lateout("a0") ret, options(nostack) @@ -65,12 +67,12 @@ pub(super) unsafe fn sys_close(fd: i32) -> i32 { } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "ecall", - in("a7") 160i32, // SYS_uname + in("a7") 160_i32, // SYS_uname in("a0") buf, lateout("a0") ret, options(nostack) @@ -79,15 +81,15 @@ pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { // asm-generic __NR_statfs routes to sys_statfs64 on 32-bit: 3-arg form. let ret: i32; - core::arch::asm!( + asm!( "ecall", - in("a7") 43i32, // __NR_statfs + in("a7") 43_i32, // __NR_statfs in("a0") path, - in("a1") core::mem::size_of::(), + in("a1") size_of::(), in("a2") buf, lateout("a0") ret, options(nostack) @@ -96,10 +98,10 @@ pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "ecall", in("a7") 179_i32, // __NR_sysinfo in("a0") info, @@ -110,16 +112,16 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "ecall", - in("a7") 123i32, // __NR_sched_getaffinity + in("a7") 123_i32, // __NR_sched_getaffinity in("a0") pid, in("a1") mask_size, in("a2") mask, @@ -130,11 +132,11 @@ pub(super) unsafe fn sys_sched_getaffinity( } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "ecall", - in("a7") 93i32, // SYS_exit + in("a7") 93_i32, // SYS_exit in("a0") code, options(noreturn, nostack) ); diff --git a/crates/asm/src/riscv64.rs b/crates/asm/src/riscv64.rs index 2a0c10b..2433afe 100644 --- a/crates/asm/src/riscv64.rs +++ b/crates/asm/src/riscv64.rs @@ -1,34 +1,33 @@ //! Syscall implementations for `riscv64`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { - let fd: i64; - core::arch::asm!( + let ret: i32; + asm!( "ecall", - in("a7") 56i64, // SYS_openat - in("a0") -100i32, // AT_FDCWD + in("a7") 56_i64, // SYS_openat + in("a0") -100_i32, // AT_FDCWD in("a1") path, in("a2") flags, - in("a3") 0i32, // mode - lateout("a0") fd, + in("a3") 0_i32, // mode + lateout("a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - fd as i32 - } + ret } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "ecall", - in("a7") 63i64, // SYS_read + in("a7") 63_i64, // SYS_read in("a0") fd, in("a1") buf, in("a2") count, @@ -36,19 +35,16 @@ pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "ecall", - in("a7") 64i64, // SYS_write + in("a7") 64_i64, // SYS_write in("a0") fd, in("a1") buf, in("a2") count, @@ -56,71 +52,59 @@ pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "ecall", - in("a7") 57i64, // SYS_close + in("a7") 57_i64, // SYS_close in("a0") fd, lateout("a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "ecall", - in("a7") 160i64, // SYS_uname + in("a7") 160_i64, // SYS_uname in("a0") buf, lateout("a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "ecall", - in("a7") 43i64, // SYS_statfs + in("a7") 43_i64, // SYS_statfs in("a0") path, in("a1") buf, lateout("a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i64; - core::arch::asm!( + asm!( "ecall", in("a7") 179_i64, // __NR_sysinfo in("a0") info, @@ -131,34 +115,31 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "ecall", - in("a7") 123i64, // __NR_sched_getaffinity + in("a7") 123_i64, // __NR_sched_getaffinity in("a0") pid, in("a1") mask_size, in("a2") mask, lateout("a0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "ecall", - in("a7") 93i64, // SYS_exit + in("a7") 93_i64, // SYS_exit in("a0") code, options(noreturn, nostack) ); diff --git a/crates/asm/src/s390x.rs b/crates/asm/src/s390x.rs index 3112ed6..243b227 100644 --- a/crates/asm/src/s390x.rs +++ b/crates/asm/src/s390x.rs @@ -1,120 +1,104 @@ //! Syscall implementations for `s390x`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { - let fd: i64; - core::arch::asm!( + let ret: i32; + asm!( "svc 0", - in("r1") 5i64, // SYS_open + in("r1") 5_i64, // SYS_open in("r2") path, in("r3") flags, - in("r4") 0i32, // mode - lateout("r2") fd, + in("r4") 0_i32, // mode + lateout("r2") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - fd as i32 - } + ret } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "svc 0", - in("r1") 3i64, // SYS_read + in("r1") 3_i64, // SYS_read in("r2") fd, in("r3") buf, in("r4") count, lateout("r2") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "svc 0", - in("r1") 4i64, // SYS_write + in("r1") 4_i64, // SYS_write in("r2") fd, in("r3") buf, in("r4") count, lateout("r2") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "svc 0", - in("r1") 6i64, // SYS_close + in("r1") 6_i64, // SYS_close in("r2") fd, lateout("r2") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "svc 0", - in("r1") 122i64, // SYS_uname + in("r1") 122_i64, // SYS_uname in("r2") buf, lateout("r2") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "svc 0", - in("r1") 99i64, // SYS_statfs + in("r1") 99_i64, // SYS_statfs in("r2") path, in("r3") buf, lateout("r2") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i64; - core::arch::asm!( + asm!( "svc 0", in("r1") 116_i64, // __NR_sysinfo in("r2") info, @@ -125,34 +109,31 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "svc 0", - in("r1") 240i64, // __NR_sched_getaffinity + in("r1") 240_i64, // __NR_sched_getaffinity in("r2") pid, in("r3") mask_size, in("r4") mask, lateout("r2") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "svc 0", - in("r1") 1i64, // SYS_exit + in("r1") 1_i64, // SYS_exit in("r2") code, options(noreturn, nostack) ); diff --git a/crates/asm/src/sparc.rs b/crates/asm/src/sparc.rs index a4cc3f7..72131bb 100644 --- a/crates/asm/src/sparc.rs +++ b/crates/asm/src/sparc.rs @@ -1,74 +1,76 @@ //! Syscall implementations for `sparc`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "mov {nr}, %g1", "ta 0x10", "bcs,a 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 5i32, // SYS_open + nr = in(reg) 5_i32, // SYS_open inlateout("o0") path => ret, in("o1") flags, - in("o2") 0i32, // mode + in("o2") 0_i32, // mode options(nostack) ); ret } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "mov {nr}, %g1", "ta 0x10", "bcs,a 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 3i32, // SYS_read + nr = in(reg) 3_i32, // SYS_read inlateout("o0") fd => ret, in("o1") buf, in("o2") count, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "mov {nr}, %g1", "ta 0x10", "bcs,a 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 4i32, // SYS_write + nr = in(reg) 4_i32, // SYS_write inlateout("o0") fd => ret, in("o1") buf, in("o2") count, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "mov {nr}, %g1", "ta 0x10", "bcs,a 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 6i32, // SYS_close + nr = in(reg) 6_i32, // SYS_close inlateout("o0") fd => ret, options(nostack) ); @@ -76,16 +78,16 @@ pub(super) unsafe fn sys_close(fd: i32) -> i32 { } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "mov {nr}, %g1", "ta 0x10", "bcs,a 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 189i32, // SYS_newuname + nr = in(reg) 189_i32, // SYS_newuname inlateout("o0") buf => ret, options(nostack) ); @@ -93,18 +95,18 @@ pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "mov {nr}, %g1", "ta 0x10", "bcs,a 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 234i32, // SYS_statfs64 + nr = in(reg) 234_i32, // SYS_statfs64 inlateout("o0") path => ret, - in("o1") core::mem::size_of::(), + in("o1") size_of::(), in("o2") buf, options(nostack) ); @@ -112,10 +114,10 @@ pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "mov {nr}, %g1", "ta 0x10", "bcs,a 1f", @@ -129,20 +131,20 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "mov {nr}, %g1", "ta 0x10", "bcs,a 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 260i32, // __NR_sched_getaffinity + nr = in(reg) 260_i32, // __NR_sched_getaffinity inlateout("o0") pid => ret, in("o1") mask_size, in("o2") mask, @@ -152,12 +154,12 @@ pub(super) unsafe fn sys_sched_getaffinity( } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "mov {nr}, %g1", "ta 0x10", - nr = in(reg) 1i32, // SYS_exit + nr = in(reg) 1_i32, // SYS_exit in("o0") code, options(noreturn, nostack) ); diff --git a/crates/asm/src/sparc64.rs b/crates/asm/src/sparc64.rs index 020657e..358a7c8 100644 --- a/crates/asm/src/sparc64.rs +++ b/crates/asm/src/sparc64.rs @@ -1,177 +1,172 @@ //! Syscall implementations for `sparc64`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "mov {nr}, %g1", "t 0x6d", "bcs,a %xcc, 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 5i64, // SYS_open - inlateout("o0") path => ret, + nr = in(reg) 5_i64, // SYS_open + in("o0") path, + lateout("o0") ret, in("o1") flags, - in("o2") 0i32, // mode + in("o2") 0_i32, // mode options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "mov {nr}, %g1", "t 0x6d", "bcs,a %xcc, 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 3i64, // SYS_read - inlateout("o0") fd as i64 => ret, + nr = in(reg) 3_i64, // SYS_read + in("o0") i64::from(fd), + lateout("o0") ret, in("o1") buf, in("o2") count, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "mov {nr}, %g1", "t 0x6d", "bcs,a %xcc, 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 4i64, // SYS_write - inlateout("o0") fd as i64 => ret, + nr = in(reg) 4_i64, // SYS_write + in("o0") i64::from(fd), + lateout("o0") ret, in("o1") buf, in("o2") count, options(nostack) ); - ret as isize + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "mov {nr}, %g1", "t 0x6d", "bcs,a %xcc, 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 6i64, // SYS_close - inlateout("o0") fd as i64 => ret, + nr = in(reg) 6_i64, // SYS_close + in("o0") i64::from(fd), + lateout("o0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "mov {nr}, %g1", "t 0x6d", "bcs,a %xcc, 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 189i64, // SYS_newuname - inlateout("o0") buf => ret, + nr = in(reg) 189_i64, // SYS_newuname + in("o0") buf, + lateout("o0") ret, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "mov {nr}, %g1", "t 0x6d", "bcs,a %xcc, 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 157i64, // SYS_statfs - inlateout("o0") path => ret, + nr = in(reg) 157_i64, // SYS_statfs + in("o0") path, + lateout("o0") ret, in("o1") buf, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i64; - core::arch::asm!( + asm!( "mov {nr}, %g1", "t 0x6d", "bcs,a %xcc, 1f", "sub %g0, %o0, %o0", "1:", nr = in(reg) 214_i64, // __NR_sysinfo - inlateout("o0") info => ret, + in("o0") info, + lateout("o0") ret, options(nostack) ); ret } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "mov {nr}, %g1", "t 0x6d", "bcs,a %xcc, 1f", "sub %g0, %o0, %o0", "1:", - nr = in(reg) 260i64, // __NR_sched_getaffinity - inlateout("o0") pid as i64 => ret, + nr = in(reg) 260_i64, // __NR_sched_getaffinity + in("o0") i64::from(pid), + lateout("o0") ret, in("o1") mask_size, in("o2") mask, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "mov {nr}, %g1", "t 0x6d", - nr = in(reg) 1i64, // SYS_exit + nr = in(reg) 1_i64, // SYS_exit in("o0") code, options(noreturn, nostack) ); diff --git a/crates/asm/src/x86.rs b/crates/asm/src/x86.rs index f0e619e..cc454ac 100644 --- a/crates/asm/src/x86.rs +++ b/crates/asm/src/x86.rs @@ -1,109 +1,111 @@ //! Syscall implementations for `x86`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; -pub(super) unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { +pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "push ebx", "mov ebx, {arg1:e}", "int 0x80", "pop ebx", arg1 = in(reg) path, - inlateout("eax") 5i32 => ret, // SYS_open + inlateout("eax") 5_i32 => ret, // SYS_open in("ecx") flags, - in("edx") 0i32, // mode + in("edx") 0_i32, // mode ); ret } } -pub(super) unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { +pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "push ebx", "mov ebx, {arg1:e}", "int 0x80", "pop ebx", arg1 = in(reg) fd, - inlateout("eax") 3i32 => ret, // SYS_read + inlateout("eax") 3_i32 => ret, // SYS_read in("ecx") buf, in("edx") count, ); - ret as isize + ret } } -pub(super) unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { +pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i32; - core::arch::asm!( + let ret: isize; + asm!( "push ebx", "mov ebx, {arg1:e}", "int 0x80", "pop ebx", arg1 = in(reg) fd, - inlateout("eax") 4i32 => ret, // SYS_write + inlateout("eax") 4_i32 => ret, // SYS_write in("ecx") buf, in("edx") count, ); - ret as isize + ret } } -pub(super) unsafe fn sys_close(fd: i32) -> i32 { +pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "push ebx", "mov ebx, {arg1:e}", "int 0x80", "pop ebx", arg1 = in(reg) fd, - inlateout("eax") 6i32 => ret, // SYS_close + inlateout("eax") 6_i32 => ret, // SYS_close ); ret } } -pub(super) unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { +pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "push ebx", "mov ebx, {arg1:e}", "int 0x80", "pop ebx", arg1 = in(reg) buf, - inlateout("eax") 122i32 => ret, // SYS_newuname + inlateout("eax") 122_i32 => ret, // SYS_newuname ); ret } } -pub(super) unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { +pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "push ebx", "mov ebx, {arg1:e}", "int 0x80", "pop ebx", arg1 = in(reg) path, - inlateout("eax") 268i32 => ret, // SYS_statfs64 - in("ecx") core::mem::size_of::(), + inlateout("eax") 268_i32 => ret, // SYS_statfs64 + in("ecx") size_of::(), in("edx") buf, ); ret } } -pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { +pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "push ebx", "mov ebx, {arg1:e}", "int 0x80", @@ -115,20 +117,20 @@ pub(super) unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { } } -pub(super) unsafe fn sys_sched_getaffinity( +pub unsafe fn sys_sched_getaffinity( pid: i32, mask_size: usize, mask: *mut u8, ) -> i32 { unsafe { let ret: i32; - core::arch::asm!( + asm!( "push ebx", "mov ebx, {arg1:e}", "int 0x80", "pop ebx", arg1 = in(reg) pid, - inlateout("eax") 242i32 => ret, // __NR_sched_getaffinity + inlateout("eax") 242_i32 => ret, // __NR_sched_getaffinity in("ecx") mask_size, in("edx") mask, ); @@ -136,13 +138,13 @@ pub(super) unsafe fn sys_sched_getaffinity( } } -pub(super) unsafe fn sys_exit(code: i32) -> ! { +pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "mov ebx, {code:e}", "int 0x80", code = in(reg) code, - in("eax") 1i32, // SYS_exit + in("eax") 1_i32, // SYS_exit options(noreturn) ); } diff --git a/crates/asm/src/x86_64.rs b/crates/asm/src/x86_64.rs index e6e0cdd..3aa4dab 100644 --- a/crates/asm/src/x86_64.rs +++ b/crates/asm/src/x86_64.rs @@ -1,34 +1,33 @@ //! Syscall implementations for `x86_64`. +use core::arch::asm; + use super::{StatfsBuf, SysInfo, UtsNameBuf}; pub unsafe fn sys_open(path: *const u8, flags: i32) -> i32 { unsafe { - let fd: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall", - in("rax") 2i64, // SYS_open + in("rax") 2_i64, // SYS_open in("rdi") path, in("rsi") flags, - in("rdx") 0i32, // mode (not used for reading) - lateout("rax") fd, + in("rdx") 0_i32, // mode (not used for reading) + lateout("rax") ret, lateout("rcx") _, lateout("r11") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - fd as i32 - } + ret } } pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "syscall", - in("rax") 0i64, // SYS_read + in("rax") 0_i64, // SYS_read in("rdi") fd, in("rsi") buf, in("rdx") count, @@ -38,19 +37,16 @@ pub unsafe fn sys_read(fd: i32, buf: *mut u8, count: usize) -> isize { options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { unsafe { - let ret: i64; - core::arch::asm!( + let ret: isize; + asm!( "syscall", - in("rax") 1i64, // SYS_write + in("rax") 1_i64, // SYS_write in("rdi") fd, in("rsi") buf, in("rdx") count, @@ -60,38 +56,32 @@ pub unsafe fn sys_write(fd: i32, buf: *const u8, count: usize) -> isize { options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as isize - } + ret } } pub unsafe fn sys_close(fd: i32) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall", - in("rax") 3i64, // SYS_close + in("rax") 3_i64, // SYS_close in("rdi") fd, lateout("rax") ret, lateout("rcx") _, lateout("r11") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall", - in("rax") 63i64, // SYS_uname + in("rax") 63_i64, // SYS_uname in("rdi") buf, lateout("rax") ret, lateout("rcx") _, @@ -99,19 +89,16 @@ pub unsafe fn sys_uname(buf: *mut UtsNameBuf) -> i32 { options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall", - in("rax") 137i64, // SYS_statfs + in("rax") 137_i64, // SYS_statfs in("rdi") path, in("rsi") buf, lateout("rax") ret, @@ -120,17 +107,14 @@ pub unsafe fn sys_statfs(path: *const u8, buf: *mut StatfsBuf) -> i32 { options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } pub unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { unsafe { let ret: i64; - core::arch::asm!( + asm!( "syscall", in("rax") 99_i64, // __NR_sysinfo in("rdi") info, @@ -149,10 +133,10 @@ pub unsafe fn sys_sched_getaffinity( mask: *mut u8, ) -> i32 { unsafe { - let ret: i64; - core::arch::asm!( + let ret: i32; + asm!( "syscall", - in("rax") 204i64, // __NR_sched_getaffinity + in("rax") 204_i64, // __NR_sched_getaffinity in("rdi") pid, in("rsi") mask_size, in("rdx") mask, @@ -161,18 +145,15 @@ pub unsafe fn sys_sched_getaffinity( lateout("r11") _, options(nostack) ); - #[allow(clippy::cast_possible_truncation)] - { - ret as i32 - } + ret } } pub unsafe fn sys_exit(code: i32) -> ! { unsafe { - core::arch::asm!( + asm!( "syscall", - in("rax") 60i64, // SYS_exit + in("rax") 60_i64, // SYS_exit in("rdi") code, options(noreturn, nostack) ); diff --git a/crates/benchmarks/Cargo.toml b/crates/benchmarks/Cargo.toml index 89fd67c..0c31c4b 100644 --- a/crates/benchmarks/Cargo.toml +++ b/crates/benchmarks/Cargo.toml @@ -8,10 +8,9 @@ license.workspace = true publish = false [dependencies] -criterion.workspace = true -criterion-cycles-per-byte.workspace = true -hotpath = { optional = true, version = "0.28.3" } -microfetch-lib.workspace = true +criterion.workspace = true +hotpath = { optional = true, version = "0.28.3" } +microfetch-lib.workspace = true [features] hotpath = [ "dep:hotpath", "hotpath/hotpath", "microfetch-lib/hotpath" ] diff --git a/crates/benchmarks/benches/microfetch.rs b/crates/benchmarks/benches/microfetch.rs index a44bf68..df863b2 100644 --- a/crates/benchmarks/benches/microfetch.rs +++ b/crates/benchmarks/benches/microfetch.rs @@ -1,4 +1,4 @@ -use std::{hint::black_box, mem::MaybeUninit}; +use core::{hint::black_box, mem::MaybeUninit}; use criterion::{Criterion, criterion_group, criterion_main}; use microfetch_lib::{ @@ -12,96 +12,100 @@ use microfetch_lib::{ uptime, }; -fn main_benchmark(c: &mut Criterion) { +#[expect( + clippy::expect_used, + reason = "the benchmarks cannot run without uname" +)] +fn main_benchmark(criterion: &mut Criterion) { let utsname = UtsName::uname().expect("Failed to get uname"); let colors = Colors::new(false); - c.bench_function("user_info", |b| { - b.iter(|| { + criterion.bench_function("user_info", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - system::write_username_and_hostname(&mut w, &colors, &utsname); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + system::write_username_and_hostname(&mut writer, &colors, &utsname); + black_box(writer.written()); }); }); - c.bench_function("os_name", |b| { - b.iter(|| { + criterion.bench_function("os_name", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - let _ = release::write_os_pretty_name(&mut w); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + release::write_os_pretty_name(&mut writer); + black_box(writer.written()); }); }); - c.bench_function("kernel_version", |b| { - b.iter(|| { + criterion.bench_function("kernel_version", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - release::write_system_info(&mut w, &utsname); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + release::write_system_info(&mut writer, &utsname); + black_box(writer.written()); }); }); - c.bench_function("cpu_name", |b| { - b.iter(|| { + criterion.bench_function("cpu_name", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - cpu::write_cpu_name(&mut w); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + cpu::write_cpu_name(&mut writer); + black_box(writer.written()); }); }); - c.bench_function("cpu_cores", |b| { - b.iter(|| { + criterion.bench_function("cpu_cores", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - let _ = cpu::write_cpu_cores(&mut w); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + cpu::write_cpu_cores(&mut writer); + black_box(writer.written()); }); }); - c.bench_function("shell", |b| { - b.iter(|| { + criterion.bench_function("shell", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - system::write_shell(&mut w); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + system::write_shell(&mut writer); + black_box(writer.written()); }); }); - c.bench_function("desktop", |b| { - b.iter(|| { + criterion.bench_function("desktop", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - desktop::write_desktop_info(&mut w); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + desktop::write_desktop_info(&mut writer); + black_box(writer.written()); }); }); - c.bench_function("uptime", |b| { - b.iter(|| { + criterion.bench_function("uptime", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - let _ = uptime::write_uptime(&mut w); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + uptime::write(&mut writer); + black_box(writer.written()); }); }); - c.bench_function("memory_usage", |b| { - b.iter(|| { + criterion.bench_function("memory_usage", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - let _ = system::write_memory_usage(&mut w, &colors); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + system::write_memory_usage(&mut writer, &colors); + black_box(writer.written()); }); }); - c.bench_function("storage", |b| { - b.iter(|| { + criterion.bench_function("storage", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - let _ = system::write_root_disk_usage(&mut w, &colors); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + system::write_root_disk_usage(&mut writer, &colors); + black_box(writer.written()); }); }); - c.bench_function("colors", |b| { - b.iter(|| { + criterion.bench_function("colors", |bencher| { + bencher.iter(|| { let mut buf = [MaybeUninit::uninit(); 256]; - let mut w = StackWriter::new(&mut buf); - colors::write_dots(&mut w, &colors); - black_box(w.written()); + let mut writer = StackWriter::new(&mut buf); + colors::write_dots(&mut writer, &colors); + black_box(writer.written()); }); }); } diff --git a/crates/benchmarks/examples/hotpath.rs b/crates/benchmarks/examples/hotpath.rs index d80b43d..1e87a90 100644 --- a/crates/benchmarks/examples/hotpath.rs +++ b/crates/benchmarks/examples/hotpath.rs @@ -2,19 +2,29 @@ //! `no_std` with its own `_start`, so it cannot host hotpath; this runs the //! same `microfetch_lib::run` from a regular std binary instead. -use std::{ffi::CString, os::unix::ffi::OsStringExt, ptr}; +extern crate alloc; +use alloc::ffi::CString; +use core::ptr; +use std::{env, os::unix::ffi::OsStringExt as _}; + +#[expect( + clippy::expect_used, + reason = "a profiling example has nowhere to report errors" +)] fn main() { - let env: Vec = std::env::vars_os() + let env = env::vars_os() .map(|(key, value)| { let mut entry = key.into_vec(); entry.push(b'='); entry.extend(value.into_vec()); CString::new(entry).expect("environment entries contain no NUL bytes") }) - .collect(); - let mut envp: Vec<*const u8> = - env.iter().map(|entry| entry.as_ptr().cast()).collect(); + .collect::>(); + let mut envp = env + .iter() + .map(|entry| entry.as_ptr().cast::()) + .collect::>(); envp.push(ptr::null()); let argv = [c"microfetch".as_ptr().cast::(), ptr::null()]; diff --git a/crates/lib/build.rs b/crates/lib/build.rs deleted file mode 100644 index f6bdf9e..0000000 --- a/crates/lib/build.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Pack logo rows into a marker-delimited stream: -// 1 = blue, 2 = cyan, 0 = row separator. -fn main() { - let rows: &[&[(u8, &str)]] = &[ - &[(0, "⠀⠀⠀⠀⠀⠀⢼⣿⣄⠀⠀⠀"), (1, "⠹⣿⣷⡀⠀⣠⣿⡧⠀⠀⠀⠀⠀⠀")], - &[(0, "⠀⠀⠀⠀⠀⠀⠈⢿⣿⣆⠀⠀⠀"), (1, "⠘⣿⣿⣴⣿⡿⠁⠀⠀⠀⠀⠀⠀")], - &[(0, "⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡜"), (1, "⢿⣿⣟⠀⠀⠀"), (0, "⢀⡄⠀⠀⠀")], - &[ - (0, "⠀⠀⠀⠉⠉⠉⠉"), - (1, "⣩⣭⡭"), - (0, "⠉⠉⠉⠉⠉"), - (1, "⠈⢿⣿⣆⠀"), - (0, "⢠⣿⣿⠂⠀⠀"), - ], - &[(1, "⠀⠀⠀⠀⠀⠀⣼⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⢻⡟"), (0, "⣡⣿⣿⠃⠀⠀⠀")], - &[(1, "⢸⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀"), (0, "⣰⣿⣿⣿⣿⣿⣿⡇")], - &[(1, "⠀⠀⠀⢠⣿⣿⢋"), (0, "⣼⣧⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⡟⠀⠀⠀⠀⠀⠀")], - &[ - (1, "⠀⠀⠠⣿⣿⠃⠀"), - (0, "⠹⣿⣷⡀"), - (1, "⣀⣀⣀⣀⣀"), - (0, "⣚⣛⣋"), - (1, "⣀⣀⣀⣀⠀⠀⠀"), - ], - &[(1, "⠀⠀⠀⠘⠁⠀⠀⠀"), (0, "⣽⣿⣷⡜"), (1, "⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀")], - &[(0, "⠀⠀⠀⠀⠀⠀⢀⣾⣿⠟⣿⣿⡄⠀⠀⠀"), (1, "⠹⣿⣷⡀⠀⠀⠀⠀⠀⠀")], - &[(0, "⠀⠀⠀⠀⠀⠀⢺⣿⠋⠀⠈⢿⣿⣆⠀⠀⠀"), (1, "⠙⣿⡗⠀⠀⠀⠀⠀⠀")], - ]; - - let mut out = Vec::new(); - for (i, row) in rows.iter().enumerate() { - for &(color, text) in *row { - out.push(color + 1); - out.extend_from_slice(text.as_bytes()); - } - if i < rows.len() - 1 { - out.push(0); - } - } - - let out_dir = std::env::var("OUT_DIR").unwrap(); - std::fs::write(format!("{out_dir}/logo.bin"), &out).unwrap(); -} diff --git a/crates/lib/src/colors.rs b/crates/lib/src/colors.rs index ead3acd..8373b3d 100644 --- a/crates/lib/src/colors.rs +++ b/crates/lib/src/colors.rs @@ -1,6 +1,6 @@ use crate::StackWriter; -/// Color codes for terminal output +/// Color codes for terminal output. pub struct Colors { pub reset: &'static str, pub blue: &'static str, @@ -12,7 +12,7 @@ pub struct Colors { } impl Colors { - #[must_use] + #[must_use = "this builds a palette without side effects"] pub const fn new(is_no_color: bool) -> Self { if is_no_color { Self { @@ -44,8 +44,8 @@ pub(crate) fn is_no_color() -> bool { } #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_dots(w: &mut StackWriter, colors: &Colors) { - for c in [ +pub fn write_dots(writer: &mut StackWriter, colors: &Colors) { + for color in [ colors.blue, colors.cyan, colors.green, @@ -53,8 +53,8 @@ pub fn write_dots(w: &mut StackWriter, colors: &Colors) { colors.red, colors.magenta, ] { - w.push_str(c); - w.push_str("● "); + writer.push_str(color); + writer.push_str("\u{25cf} "); } - w.push_str(colors.reset); + writer.push_str(colors.reset); } diff --git a/crates/lib/src/cpu.rs b/crates/lib/src/cpu.rs index 06c9981..b73a9d1 100644 --- a/crates/lib/src/cpu.rs +++ b/crates/lib/src/cpu.rs @@ -1,122 +1,115 @@ +use core::str; + #[cfg(target_os = "linux")] -use crate::syscall::read_file_fast; -use crate::{Error, StackWriter}; +use microfetch_asm::read_file_fast; + +use crate::StackWriter; /// Writes CPU model name (trimmed) to the writer. #[cfg(target_os = "linux")] #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_cpu_name(w: &mut StackWriter) { - write_model_name(w); +pub fn write_cpu_name(writer: &mut StackWriter) { + write_model_name(writer); } /// Writes CPU model name from `machdep.cpu.brand_string` (macOS), /// e.g. `Apple M2 Pro`. Returns an empty string if unavailable. #[cfg(target_os = "macos")] #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_cpu_name(w: &mut StackWriter) { - let mut buf = [0u8; 128]; - if let Some(n) = - crate::syscall::macos_sysctl_str(b"machdep.cpu.brand_string\0", &mut buf) +pub fn write_cpu_name(writer: &mut StackWriter) { + use microfetch_asm::darwin::macos_sysctl_str; + + let mut buf = [0_u8; 128]; + if let Some(len) = macos_sysctl_str(b"machdep.cpu.brand_string\0", &mut buf) + && let Ok(name) = str::from_utf8(&buf[..len]) { - if let Ok(name) = core::str::from_utf8(&buf[..n]) { - w.push_str(name); - } + writer.push_str(name); } } /// Writes CPU core/thread info string. /// /// Format: `{cores} cores ({p}p/{e}e), {threads} threads` on hybrid Intel, -/// `{cores} cores, {threads} threads` otherwise. -/// -/// # Errors -/// -/// Returns an error if the thread count cannot be determined. +/// `{cores} cores, {threads} threads` otherwise. Writes nothing if the thread +/// count cannot be determined. #[cfg(target_os = "linux")] #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_cpu_cores(w: &mut StackWriter) -> Result<(), Error> { - let threads = get_thread_count()?; +pub fn write_cpu_cores(writer: &mut StackWriter) { + let Some(threads) = get_thread_count() else { + return; + }; let cores = get_core_count(threads); - write_cores(w, cores, get_pe_cores(), threads); - Ok(()) + write_cores(writer, cores, get_pe_cores(), threads); } /// Writes CPU core/thread info via `sysctl` (macOS). /// /// On Apple Silicon `hw.perflevel0`/`hw.perflevel1` expose the performance -/// (P) and efficiency (E) core counts respectively. -/// -/// # Errors -/// -/// Returns an error if the logical CPU count cannot be determined. +/// (P) and efficiency (E) core counts respectively. Writes nothing if the +/// logical CPU count cannot be determined. #[cfg(target_os = "macos")] #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_cpu_cores(w: &mut StackWriter) -> Result<(), Error> { - use crate::syscall::macos_sysctl_u32; +pub fn write_cpu_cores(writer: &mut StackWriter) { + use microfetch_asm::darwin::macos_sysctl_u32; - let threads = - macos_sysctl_u32(b"hw.logicalcpu\0").ok_or(Error::OsError(0))?; + let Some(threads) = macos_sysctl_u32(b"hw.logicalcpu\0") else { + return; + }; let cores = macos_sysctl_u32(b"hw.physicalcpu\0").unwrap_or(threads); // Performance/efficiency split (Apple Silicon). Only reported when both // perf levels are present. - let pe = match ( + let hybrid = match ( macos_sysctl_u32(b"hw.perflevel0.physicalcpu\0"), macos_sysctl_u32(b"hw.perflevel1.physicalcpu\0"), ) { - (Some(p), Some(e)) => Some((p, e)), + (Some(perf), Some(eff)) => Some((perf, eff)), _ => None, }; - write_cores(w, cores, pe, threads); - Ok(()) + write_cores(writer, cores, hybrid, threads); } /// Writes core/thread counts identically across platforms: /// `{cores} cores ({p}p/{e}e), {threads} threads`, omitting the P/E group and /// the thread suffix when not applicable. fn write_cores( - w: &mut StackWriter, + writer: &mut StackWriter, cores: u32, - pe: Option<(u32, u32)>, + hybrid: Option<(u32, u32)>, threads: u32, ) { - w.push_u64(u64::from(cores)); - w.push_str(" cores"); - - if let Some((p, e)) = pe { - w.push_str(" ("); - w.push_u64(u64::from(p)); - w.push_str("p/"); - w.push_u64(u64::from(e)); - w.push_str("e)"); + writer.push_u64(u64::from(cores)); + writer.push_str(" cores"); + + if let Some((perf, eff)) = hybrid { + writer.push_str(" ("); + writer.push_u64(u64::from(perf)); + writer.push_str("p/"); + writer.push_u64(u64::from(eff)); + writer.push_str("e)"); } if threads != cores { - w.push_str(", "); - w.push_u64(u64::from(threads)); - w.push_str(" threads"); + writer.push_str(", "); + writer.push_u64(u64::from(threads)); + writer.push_str(" threads"); } } /// Count online threads via `sched_getaffinity(2)`. #[cfg(target_os = "linux")] -fn get_thread_count() -> Result { - let mut mask = [0u8; 128]; +fn get_thread_count() -> Option { + let mut mask = [0_u8; 128]; let ret = unsafe { - crate::syscall::sys_sched_getaffinity(0, mask.len(), mask.as_mut_ptr()) + microfetch_asm::sys_sched_getaffinity(0, mask.len(), mask.as_mut_ptr()) }; - if ret < 0 { - return Err(Error::from_raw_os_error(-ret)); - } - - #[allow(clippy::cast_sign_loss)] - let bytes = ret as usize; - let mut count = 0u32; + let bytes = usize::try_from(ret).ok()?; + let mut count = 0_u32; for &byte in &mask[..bytes] { count += byte.count_ones(); } - Ok(count) + Some(count) } /// Derive physical core count from thread count and topology. @@ -137,26 +130,26 @@ fn get_core_count(threads: u32) -> u32 { /// by reading `/sys/devices/cpu_core/cpus` and `/sys/devices/cpu_atom/cpus`. #[cfg(target_os = "linux")] fn get_pe_cores() -> Option<(u32, u32)> { - let p = count_cpulist("/sys/devices/cpu_core/cpus")?; - let e = count_cpulist("/sys/devices/cpu_atom/cpus").unwrap_or(0); - if p > 0 || e > 0 { Some((p, e)) } else { None } + let perf = count_cpulist("/sys/devices/cpu_core/cpus")?; + let eff = count_cpulist("/sys/devices/cpu_atom/cpus").unwrap_or(0); + (perf > 0 || eff > 0).then_some((perf, eff)) } /// Parse a cpulist file and count listed CPUs. #[cfg(target_os = "linux")] fn count_cpulist(path: &str) -> Option { - let mut buf = [0u8; 64]; - let n = read_file_fast(path, &mut buf).ok()?; - let data = &buf[..n]; + let mut buf = [0_u8; 64]; + let len = read_file_fast(path, &mut buf).ok()?; + let data = &buf[..len]; - let mut count = 0u32; - let mut i = 0; - while i < data.len() { + let mut count = 0_u32; + let mut pos = 0; + while pos < data.len() { // Parse start number - let start = parse_num(data, &mut i); - if i < data.len() && data[i] == b'-' { - i += 1; - let end = parse_num(data, &mut i); + let start = parse_num(data, &mut pos); + if pos < data.len() && data[pos] == b'-' { + pos += 1; + let end = parse_num(data, &mut pos); // The Kernel always emits ascending ranges, so end is always >= start // https://github.com/torvalds/linux/blob/v6.19/lib/vsprintf.c#L1276-L1303 count += end - start + 1; @@ -164,8 +157,8 @@ fn count_cpulist(path: &str) -> Option { count += 1; } // Skip comma or newline - if i < data.len() && (data[i] == b',' || data[i] == b'\n') { - i += 1; + if pos < data.len() && (data[pos] == b',' || data[pos] == b'\n') { + pos += 1; } } Some(count) @@ -173,13 +166,13 @@ fn count_cpulist(path: &str) -> Option { /// Parse a decimal number from a byte slice, advancing the index. #[cfg(target_os = "linux")] -fn parse_num(data: &[u8], i: &mut usize) -> u32 { - let mut n = 0u32; - while *i < data.len() && data[*i].is_ascii_digit() { - n = n * 10 + u32::from(data[*i] - b'0'); - *i += 1; +fn parse_num(data: &[u8], pos: &mut usize) -> u32 { + let mut value = 0_u32; + while *pos < data.len() && data[*pos].is_ascii_digit() { + value = value * 10 + u32::from(data[*pos] - b'0'); + *pos += 1; } - n + value } /// Build `/sys/devices/system/cpu/cpu{n}/cpufreq/cpuinfo_max_freq` into buf, @@ -189,41 +182,41 @@ fn format_cpufreq_path(buf: &mut [u8; 64], cpu: u32) -> usize { const PREFIX: &[u8] = b"/sys/devices/system/cpu/cpu"; const SUFFIX: &[u8] = b"/cpufreq/cpuinfo_max_freq"; buf[..PREFIX.len()].copy_from_slice(PREFIX); - let mut i = PREFIX.len(); - let mut tmp = [0u8; 3]; - let mut n = cpu; + let mut pos = PREFIX.len(); + let mut tmp = [0_u8; 3]; + let mut value = cpu; let mut digits = 0; loop { - tmp[digits] = b'0' + (n % 10) as u8; + tmp[digits] = b'0' + u8::try_from(value % 10).unwrap_or(0); digits += 1; - n /= 10; - if n == 0 { + value /= 10; + if value == 0 { break; } } while digits > 0 { digits -= 1; - buf[i] = tmp[digits]; - i += 1; + buf[pos] = tmp[digits]; + pos += 1; } - buf[i..i + SUFFIX.len()].copy_from_slice(SUFFIX); - i + SUFFIX.len() + buf[pos..pos + SUFFIX.len()].copy_from_slice(SUFFIX); + pos + SUFFIX.len() } /// Read one CPU's `cpuinfo_max_freq`, in kHz. #[cfg(target_os = "linux")] fn read_cpu_max_khz(cpu: u32) -> Option { - let mut path = [0u8; 64]; - let n = format_cpufreq_path(&mut path, cpu); + let mut path = [0_u8; 64]; + let path_len = format_cpufreq_path(&mut path, cpu); // SAFETY: the path is a constant prefix, decimal digits, and a constant // suffix, so it is ASCII by construction. - let p = unsafe { core::str::from_utf8_unchecked(&path[..n]) }; - let mut buf = [0u8; 32]; - let m = read_file_fast(p, &mut buf).ok()?; - let mut khz = 0u32; - for &b in &buf[..m] { - if b.is_ascii_digit() { - khz = khz * 10 + u32::from(b - b'0'); + let path_str = unsafe { str::from_utf8_unchecked(&path[..path_len]) }; + let mut buf = [0_u8; 32]; + let len = read_file_fast(path_str, &mut buf).ok()?; + let mut khz = 0_u32; + for &byte in &buf[..len] { + if byte.is_ascii_digit() { + khz = khz * 10 + u32::from(byte - b'0'); } } (khz > 0).then_some(khz) @@ -234,17 +227,17 @@ fn read_cpu_max_khz(cpu: u32) -> Option { // https://github.com/torvalds/linux/blob/v6.19/drivers/base/cpu.c#L273-L286 #[cfg(target_os = "linux")] fn highest_present_cpu() -> Option { - let mut buf = [0u8; 64]; - let n = read_file_fast("/sys/devices/system/cpu/present", &mut buf).ok()?; - let data = &buf[..n]; + let mut buf = [0_u8; 64]; + let len = read_file_fast("/sys/devices/system/cpu/present", &mut buf).ok()?; + let data = &buf[..len]; let end = data.iter().rposition(u8::is_ascii_digit)? + 1; let start = data[..end] .iter() - .rposition(|b| !b.is_ascii_digit()) - .map_or(0, |i| i + 1); - let mut cpu = 0u32; - for &b in &data[start..end] { - cpu = cpu * 10 + u32::from(b - b'0'); + .rposition(|byte| !byte.is_ascii_digit()) + .map_or(0, |pos| pos + 1); + let mut cpu = 0_u32; + for &byte in &data[start..end] { + cpu = cpu * 10 + u32::from(byte - b'0'); } Some(cpu) } @@ -280,7 +273,7 @@ fn get_cpu_freq_mhz(cpuinfo: &[u8]) -> Option { } // Fall back to cpuinfo fields for key in &[ - b"cpu MHz" as &[u8], + b"cpu MHz".as_slice(), b"cpu MHz dynamic", b"cpu MHz static", b"CPU MHz", @@ -290,20 +283,22 @@ fn get_cpu_freq_mhz(cpuinfo: &[u8]) -> Option { ] { if let Some(val) = extract_field(cpuinfo, key) { // Parse integer part of the MHz value (e.g. "5200.00" -> 5200) - let mut mhz = 0u32; - for &b in val.as_bytes() { - if b == b'.' { + let mut mhz = 0_u32; + for &byte in val.as_bytes() { + if byte == b'.' { break; } - if b.is_ascii_digit() { - mhz = mhz * 10 + u32::from(b - b'0'); + if byte.is_ascii_digit() { + mhz = mhz * 10 + u32::from(byte - b'0'); } } // Octeon presets loops_per_jiffy to clock_rate/HZ, so its BogoMIPS is // exactly 2x the core clock, unlike the 1:1 of other MIPS. // https://github.com/torvalds/linux/blob/v6.19/arch/mips/cavium-octeon/csrc-octeon.c#L40 - if *key == b"BogoMIPS" && cpuinfo.windows(6).any(|w| w == b"Octeon") { + if *key == b"BogoMIPS" + && cpuinfo.windows(6).any(|window| window == b"Octeon") + { mhz /= 2; } @@ -315,18 +310,18 @@ fn get_cpu_freq_mhz(cpuinfo: &[u8]) -> Option { // SPARC exposes its clock as `Cpu0ClkTck : `, // which signifies ticks per second in hex. if let Some(val) = extract_field(cpuinfo, b"Cpu0ClkTck") { - let mut hz = 0u64; + let mut hz = 0_u64; let mut seen = false; - for &b in val.as_bytes() { - let d = match b { - b'0'..=b'9' => Some(u64::from(b - b'0')), - b'a'..=b'f' => Some(u64::from(b - b'a' + 10)), - b'A'..=b'F' => Some(u64::from(b - b'A' + 10)), + for &byte in val.as_bytes() { + let hex_digit = match byte { + b'0'..=b'9' => Some(u64::from(byte - b'0')), + b'a'..=b'f' => Some(u64::from(byte - b'a' + 10)), + b'A'..=b'F' => Some(u64::from(byte - b'A' + 10)), _ => None, }; - match d { - Some(d) => { - hz = hz * 16 + d; + match hex_digit { + Some(digit) => { + hz = hz * 16 + digit; seen = true; }, None if seen => break, @@ -334,8 +329,7 @@ fn get_cpu_freq_mhz(cpuinfo: &[u8]) -> Option { } } if hz > 0 { - #[allow(clippy::cast_possible_truncation)] - return Some((hz / 1_000_000) as u32); + return u32::try_from(hz / 1_000_000).ok(); } } None @@ -344,37 +338,37 @@ fn get_cpu_freq_mhz(cpuinfo: &[u8]) -> Option { /// Parse CPU model name from `/proc/cpuinfo` and write it directly. /// Appends CPU frequency if available. #[cfg(target_os = "linux")] -fn write_model_name(w: &mut StackWriter) { - let mut buf = [0u8; 1024]; - let Ok(n) = read_file_fast("/proc/cpuinfo", &mut buf) else { +fn write_model_name(writer: &mut StackWriter) { + let mut buf = [0_u8; 1024]; + let Ok(len) = read_file_fast("/proc/cpuinfo", &mut buf) else { return; }; - let data = &buf[..n]; + let data = &buf[..len]; - let mhz = get_cpu_freq_mhz(data); + let freq_mhz = get_cpu_freq_mhz(data); let named = match extract_name(data) { Some(name) => { // x86 `model name` already ends in `@ GHz`, which hides the // ` CPU` that trim() would otherwise strip, so re-trim after cutting. - let name = match (mhz, name.find(" @ ")) { - (Some(_), Some(at)) => trim(&name[..at]), - _ => name, - }; - w.push_str(name); + let clock_free = name.split_once(" @ ").map(|(head, _)| head); + match (freq_mhz, clock_free) { + (Some(_), Some(head)) => writer.push_str(trim(head)), + _ => writer.push_str(name), + } true }, None => { - write_dt_compatible(w) - || (cfg!(target_arch = "aarch64") && write_arm_part(w, data)) + write_dt_compatible(writer) + || (cfg!(target_arch = "aarch64") && write_arm_part(writer, data)) }, }; - let Some(mhz) = mhz else { + let Some(mhz) = freq_mhz else { return; }; if named { - w.push_str(" @ "); + writer.push_str(" @ "); } // Round to nearest 0.01 GHz, then split so carries (e.g. 1999 MHz) @@ -382,13 +376,13 @@ fn write_model_name(w: &mut StackWriter) { let rounded_centesimal = (mhz + 5) / 10; let ghz_int = rounded_centesimal / 100; let ghz_frac = rounded_centesimal % 100; - w.push_u64(u64::from(ghz_int)); - w.push_byte(b'.'); + writer.push_u64(u64::from(ghz_int)); + writer.push_byte(b'.'); if ghz_frac < 10 { - w.push_byte(b'0'); + writer.push_byte(b'0'); } - w.push_u64(u64::from(ghz_frac)); - w.push_str(" GHz"); + writer.push_u64(u64::from(ghz_frac)); + writer.push_str(" GHz"); } #[cfg(target_os = "linux")] @@ -429,7 +423,7 @@ struct ArmPart { #[cfg(target_os = "linux")] const fn arm_part(part: u16, family: ArmFamily, model: &str) -> ArmPart { let bytes = model.as_bytes(); - let mut padded = [0u8; 7]; + let mut padded = [0_u8; 7]; let mut index = 0; while index < bytes.len() { padded[index] = bytes[index]; @@ -497,15 +491,15 @@ static ARM_PARTS: [ArmPart; 45] = { /// Name the core from `CPU implementer` and `CPU part` on ACPI aarch64. #[cfg(target_os = "linux")] -fn write_arm_part(w: &mut StackWriter, data: &[u8]) -> bool { +fn write_arm_part(writer: &mut StackWriter, data: &[u8]) -> bool { let hex = |key| { let digits = extract_field(data, key)?.strip_prefix("0x")?; - let mut value = 0u32; + let mut value = 0_u32; for digit in digits .bytes() .map_while(|byte| char::from(byte).to_digit(16)) { - value = value << 4 | digit; + value = (value << 4_u32) | digit; } Some(value) }; @@ -522,9 +516,9 @@ fn write_arm_part(w: &mut StackWriter, data: &[u8]) -> bool { return false; }; - let len = entry.model.iter().position(|&b| b == 0).unwrap_or(7); - w.push_str(entry.family.prefix()); - w.push_bytes(&entry.model[..len]); + let len = entry.model.iter().position(|&byte| byte == 0).unwrap_or(7); + writer.push_str(entry.family.prefix()); + writer.push_bytes(&entry.model[..len]); true } @@ -532,7 +526,7 @@ fn write_arm_part(w: &mut StackWriter, data: &[u8]) -> bool { #[cfg(target_os = "linux")] fn extract_name(data: &[u8]) -> Option<&str> { for key in &[ - b"model name" as &[u8], + b"model name".as_slice(), b"Model Name", b"uarch", b"cpu model", @@ -556,60 +550,67 @@ fn extract_name(data: &[u8]) -> Option<&str> { /// (board) to most-generic (`SoC`); we take the last entry and write just /// the model portion after the comma. #[cfg(target_os = "linux")] -fn write_dt_compatible(w: &mut StackWriter) -> bool { - let mut buf = [0u8; 256]; - let Ok(n) = +fn write_dt_compatible(writer: &mut StackWriter) -> bool { + let mut buf = [0_u8; 256]; + let Ok(len) = read_file_fast("/sys/firmware/devicetree/base/compatible", &mut buf) else { return false; }; // Drop the terminating NUL so the rposition below locates the entry // separator rather than the end-of-string marker. - let end = if n > 0 && buf[n - 1] == 0 { n - 1 } else { n }; + let end = if len > 0 && buf[len - 1] == 0 { + len - 1 + } else { + len + }; let data = &buf[..end]; - let start = data.iter().rposition(|&b| b == 0).map_or(0, |p| p + 1); + let start = data + .iter() + .rposition(|&byte| byte == 0) + .map_or(0, |pos| pos + 1); let entry = &data[start..]; - let Some(comma) = entry.iter().position(|&b| b == b',') else { + let Some(comma) = entry.iter().position(|&byte| byte == b',') else { return false; }; - let Ok(model) = core::str::from_utf8(&entry[comma + 1..]) else { + let Ok(model) = str::from_utf8(&entry[comma + 1..]) else { return false; }; if model.is_empty() { return false; } - w.push_str(model); + writer.push_str(model); true } /// Extract value of first occurrence of `key` in cpuinfo. #[cfg(target_os = "linux")] -fn extract_field<'a>(data: &'a [u8], key: &[u8]) -> Option<&'a str> { - let mut i = 0; - while i < data.len() { - let remaining = &data[i..]; +fn extract_field<'data>(data: &'data [u8], key: &[u8]) -> Option<&'data str> { + let mut index = 0; + while index < data.len() { + let remaining = &data[index..]; let eol = remaining .iter() - .position(|&b| b == b'\n') + .position(|&byte| byte == b'\n') .unwrap_or(remaining.len()); let line = &remaining[..eol]; if line.starts_with(key) { - let mut p = key.len(); - while p < line.len() && (line[p] == b'\t' || line[p] == b' ') { - p += 1; + let mut pos = key.len(); + while pos < line.len() && (line[pos] == b'\t' || line[pos] == b' ') { + pos += 1; } - if p < line.len() && line[p] == b':' { - p += 1; - while p < line.len() && line[p] == b' ' { - p += 1; + if pos < line.len() && line[pos] == b':' { + pos += 1; + while pos < line.len() && line[pos] == b' ' { + pos += 1; } // SAFETY: cpuinfo fields are ASCII - return Some(unsafe { core::str::from_utf8_unchecked(&line[p..]) }); + return Some(unsafe { str::from_utf8_unchecked(&line[pos..]) }); } } - i += eol + 1; + index += eol + 1; } None } @@ -617,50 +618,29 @@ fn extract_field<'a>(data: &'a [u8], key: &[u8]) -> Option<&'a str> { /// Strip noise from model names. #[cfg(target_os = "linux")] fn trim(name: &str) -> &str { - let b = name.as_bytes(); - let mut end = b.len(); - - while end > 0 && b[end - 1].is_ascii_whitespace() { - end -= 1; - } - - if end >= 10 && &b[end - 10..end] == b" Processor" { - end -= 10; - } else if end >= 4 && &b[end - 4..end] == b" CPU" { - end -= 4; - } - while end > 0 && b[end - 1].is_ascii_whitespace() { - end -= 1; - } - - if end >= 3 && &b[end - 3..end] == b"(R)" { - end -= 3; - } else if end >= 4 - && (&b[end - 4..end] == b"(TM)" || &b[end - 4..end] == b"(tm)") + let mut rest = name.trim_ascii_end(); + + rest = rest + .strip_suffix(" Processor") + .or_else(|| rest.strip_suffix(" CPU")) + .unwrap_or(rest) + .trim_ascii_end(); + + rest = rest + .strip_suffix("(R)") + .or_else(|| rest.strip_suffix("(TM)")) + .or_else(|| rest.strip_suffix("(tm)")) + .unwrap_or(rest) + .trim_ascii_end(); + + if rest.len() > 7 + && let Some(head) = rest.strip_suffix("-Core") + && let Some(kept) = head + .trim_end_matches(|ch: char| ch.is_ascii_digit()) + .strip_suffix(' ') { - end -= 4; - } - while end > 0 && b[end - 1].is_ascii_whitespace() { - end -= 1; - } - - if end > 7 && &b[end - 5..end] == b"-Core" { - let mut p = end - 5; - while p > 0 && b[p - 1].is_ascii_digit() { - p -= 1; - } - if p > 0 && b[p - 1] == b' ' { - end = p - 1; - } - } - while end > 0 && b[end - 1].is_ascii_whitespace() { - end -= 1; - } - - let mut start = 0; - while start < end && b[start].is_ascii_whitespace() { - start += 1; + rest = kept.trim_ascii_end(); } - &name[start..end] + rest.trim_ascii_start() } diff --git a/crates/lib/src/desktop.rs b/crates/lib/src/desktop.rs index 3b5871a..d89ddc9 100644 --- a/crates/lib/src/desktop.rs +++ b/crates/lib/src/desktop.rs @@ -1,7 +1,7 @@ use crate::{StackWriter, getenv_str}; #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_desktop_info(w: &mut StackWriter) { +pub fn write_desktop_info(writer: &mut StackWriter) { let desktop_raw = getenv_str("XDG_CURRENT_DESKTOP"); let session_raw = getenv_str("XDG_SESSION_TYPE"); @@ -13,7 +13,7 @@ pub fn write_desktop_info(w: &mut StackWriter) { "Unknown" } }, - |s| s.strip_prefix("none+").unwrap_or(s), + |desktop| desktop.strip_prefix("none+").unwrap_or(desktop), ); let backend_str = session_raw.unwrap_or({ @@ -24,20 +24,14 @@ pub fn write_desktop_info(w: &mut StackWriter) { } }); - w.push_str(desktop_str); - w.push_str(" ("); + writer.push_str(desktop_str); + writer.push_str(" ("); // Capitalize first character of backend - if let Some(&first_byte) = backend_str.as_bytes().first() { - // Convert first byte to uppercase if it's ASCII lowercase - let upper = if first_byte.is_ascii_lowercase() { - first_byte - b'a' + b'A' - } else { - first_byte - }; - w.push_byte(upper); - w.push_str(&backend_str[1..]); + if let Some((&first_byte, rest)) = backend_str.as_bytes().split_first() { + writer.push_byte(first_byte.to_ascii_uppercase()); + writer.push_bytes(rest); } - w.push_byte(b')'); + writer.push_byte(b')'); } diff --git a/crates/lib/src/lib.rs b/crates/lib/src/lib.rs index d756692..1e0efc8 100644 --- a/crates/lib/src/lib.rs +++ b/crates/lib/src/lib.rs @@ -11,26 +11,16 @@ pub mod system; pub mod uptime; use core::{ + array, ffi::CStr, mem::MaybeUninit, + ptr, + slice, + str, sync::atomic::{AtomicPtr, Ordering}, }; -pub use microfetch_asm as syscall; -pub use microfetch_asm::{ - StatfsBuf, - SysInfo, - UtsNameBuf, - read_file_fast, - sys_close, - sys_open, - sys_read, - sys_sched_getaffinity, - sys_statfs, - sys_sysinfo, - sys_uname, - sys_write, -}; +use microfetch_asm::{UtsNameBuf, sys_uname, sys_write}; /// A simple error type for microfetch operations. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -48,24 +38,17 @@ pub enum Error { impl Error { /// Creates an error from the last OS error (reads errno). #[inline] - #[must_use] + #[must_use = "this only reads errno"] pub const fn last_os_error() -> Self { // This is a simplified version - in a real implementation, // we'd need to get the actual errno from the syscall return Self::OsError(0) } - - /// Creates an error from a raw OS error code (negative errno from syscall). - #[inline] - #[must_use] - pub const fn from_raw_os_error(errno: i32) -> Self { - Self::OsError(-errno) - } } // Store the environment pointer internally,initialized from `main()`. This // helps avoid the libc dependency *completely*. -static ENVP: AtomicPtr<*const u8> = AtomicPtr::new(core::ptr::null_mut()); +static ENVP: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); /// Initialize the environment pointer. Must be called before any `getenv()` /// calls. This is called from `main()` with the calculated `envp`. @@ -81,14 +64,14 @@ pub unsafe fn init_env(envp: *const *const u8) { /// Gets the current environment pointer. #[inline] -#[must_use] +#[must_use = "this only reads the stored pointer"] fn get_envp() -> *const *const u8 { ENVP.load(Ordering::Acquire) } /// Gets an environment variable by name without using std or libc by reading /// from the environment pointer set by [`init_env`]. -#[must_use] +#[must_use = "this only reads the environment"] pub fn getenv(name: &str) -> Option<&'static [u8]> { let envp = get_envp(); if envp.is_null() { @@ -98,20 +81,20 @@ pub fn getenv(name: &str) -> Option<&'static [u8]> { let name_bytes = name.as_bytes(); // Walk through environment variables - let mut i = 0; + let mut env_index = 0; loop { // SAFETY: environ is null-terminated array of pointers - let entry = unsafe { *envp.add(i) }; + let entry = unsafe { *envp.add(env_index) }; if entry.is_null() { break; } // Check if this entry starts with our variable name followed by '=' let mut matches = true; - for (j, &b) in name_bytes.iter().enumerate() { + for (name_index, &name_byte) in name_bytes.iter().enumerate() { // SAFETY: entry is a valid C string - let entry_byte = unsafe { *entry.add(j) }; - if entry_byte != b { + let entry_byte = unsafe { *entry.add(name_index) }; + if entry_byte != name_byte { matches = false; break; } @@ -127,18 +110,18 @@ pub fn getenv(name: &str) -> Option<&'static [u8]> { let mut len = 0; loop { // SAFETY: entry is a valid C string - let b = unsafe { *value_start.add(len) }; - if b == 0 { + let value_byte = unsafe { *value_start.add(len) }; + if value_byte == 0 { break; } len += 1; } // SAFETY: We calculated the exact length - return Some(unsafe { core::slice::from_raw_parts(value_start, len) }); + return Some(unsafe { slice::from_raw_parts(value_start, len) }); } } - i += 1; + env_index += 1; } None @@ -151,120 +134,120 @@ pub fn getenv(name: &str) -> Option<&'static [u8]> { /// Environment variables set by the shell / login process are always valid /// UTF-8 on any real Linux system. We skip the `from_utf8` validation and use /// `from_utf8_unchecked`. -#[must_use] +#[must_use = "this only reads the environment"] pub fn getenv_str(name: &str) -> Option<&'static str> { - getenv(name).map(|bytes| unsafe { core::str::from_utf8_unchecked(bytes) }) + getenv(name).map(|bytes| unsafe { str::from_utf8_unchecked(bytes) }) } /// Checks if an environment variable exists (regardless of its value). -#[must_use] +#[must_use = "this only reads the environment"] pub fn env_exists(name: &str) -> bool { getenv(name).is_some() } -/// Wrapper for `utsname` with safe accessor methods +/// Wrapper for `utsname` with safe accessor methods. pub struct UtsName(UtsNameBuf); impl UtsName { - /// Calls `uname(2)` syscall and returns a `UtsName` wrapper + /// Calls `uname(2)` syscall and returns a `UtsName` wrapper. /// /// # Errors /// - /// Returns an error if the `uname` syscall fails + /// Returns an error if the `uname` syscall fails. pub fn uname() -> Result { let mut uts = MaybeUninit::uninit(); - if unsafe { sys_uname(uts.as_mut_ptr()) } != 0 { + if unsafe { sys_uname(uts.as_mut_ptr()) } != 0_i32 { return Err(Error::last_os_error()); } Ok(Self(unsafe { uts.assume_init() })) } - #[must_use] + #[must_use = "this only borrows a field"] pub const fn nodename(&self) -> &CStr { unsafe { CStr::from_ptr(self.0.nodename.as_ptr().cast()) } } - #[must_use] + #[must_use = "this only borrows a field"] pub const fn sysname(&self) -> &CStr { unsafe { CStr::from_ptr(self.0.sysname.as_ptr().cast()) } } - #[must_use] + #[must_use = "this only borrows a field"] pub const fn release(&self) -> &CStr { unsafe { CStr::from_ptr(self.0.release.as_ptr().cast()) } } - #[must_use] + #[must_use = "this only borrows a field"] pub const fn machine(&self) -> &CStr { unsafe { CStr::from_ptr(self.0.machine.as_ptr().cast()) } } } /// Minimal, stack-allocated writer. -pub struct StackWriter<'a> { - buf: &'a mut [MaybeUninit], +pub struct StackWriter<'buf> { + buf: &'buf mut [MaybeUninit], pos: usize, } -impl<'a> StackWriter<'a> { +impl<'buf> StackWriter<'buf> { #[inline] - pub const fn new(buf: &'a mut [MaybeUninit]) -> Self { + pub const fn new(buf: &'buf mut [MaybeUninit]) -> Self { Self { buf, pos: 0 } } #[inline] - #[must_use] - pub fn written(&self) -> &[u8] { - unsafe { core::slice::from_raw_parts(self.buf.as_ptr().cast(), self.pos) } + #[must_use = "this only borrows the written bytes"] + pub const fn written(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.buf.as_ptr().cast(), self.pos) } } #[inline] - pub fn push_str(&mut self, s: &str) { - self.push_bytes(s.as_bytes()); + pub fn push_str(&mut self, text: &str) { + self.push_bytes(text.as_bytes()); } #[inline(never)] pub fn push_bytes(&mut self, bytes: &[u8]) { - let n = bytes.len().min(self.buf.len() - self.pos); + let len = bytes.len().min(self.buf.len() - self.pos); unsafe { - core::ptr::copy_nonoverlapping( + ptr::copy_nonoverlapping( bytes.as_ptr(), self.buf.as_mut_ptr().add(self.pos).cast(), - n, + len, ); - } - self.pos += n; + }; + self.pos += len; } #[inline] - pub fn push_byte(&mut self, b: u8) { + pub const fn push_byte(&mut self, byte: u8) { if self.pos < self.buf.len() { - self.buf[self.pos].write(b); + self.buf[self.pos].write(byte); self.pos += 1; } } /// Write a [`CStr`]'s bytes (excluding the null terminator). #[inline] - pub fn push_cstr(&mut self, s: &CStr) { - self.push_bytes(s.to_bytes()); + pub fn push_cstr(&mut self, cstr: &CStr) { + self.push_bytes(cstr.to_bytes()); } /// Write a u64 as decimal ASCII. - pub fn push_u64(&mut self, mut n: u64) { - if n == 0 { + pub fn push_u64(&mut self, mut value: u64) { + if value == 0 { self.push_byte(b'0'); return; } - let mut tmp = [0u8; 20]; - let mut i = 20; - while n > 0 { - i -= 1; - tmp[i] = b'0' + (n % 10) as u8; - n /= 10; + let mut digits = [0_u8; 20]; + let mut start = 20; + while value > 0 { + start -= 1; + digits[start] = b'0' + u8::try_from(value % 10).unwrap_or(0); + value /= 10; } - self.push_bytes(&tmp[i..]); + self.push_bytes(&digits[start..]); } } @@ -272,42 +255,60 @@ impl<'a> StackWriter<'a> { /// environment variable. Set it to 11 newline-separated lines of ASCII/Unicode /// art when building to replace the default NixOS logo: /// -/// `MICROFETCH_LOGO="$(cat my_logo.txt)"` cargo build --release +/// ```sh +/// MICROFETCH_LOGO="$(cat my_logo.txt)" cargo build --release +/// ``` /// /// Each line maps to one info row. When unset, the built-in two-tone NixOS /// logo is used. const CUSTOM_LOGO: &str = match option_env!("MICROFETCH_LOGO") { - Some(s) => s, + Some(logo) => logo, None => "", }; /// Packed logo rows. `0` separates rows; `1` and `2` select colors. -const LOGO: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/logo.bin")); +const LOGO: &[u8] = concat!( + "\x01⠀⠀⠀⠀⠀⠀⢼⣿⣄⠀⠀⠀\x02⠹⣿⣷⡀⠀⣠⣿⡧⠀⠀⠀⠀⠀⠀\0", + "\x01⠀⠀⠀⠀⠀⠀⠈⢿⣿⣆⠀⠀⠀\x02⠘⣿⣿⣴⣿⡿⠁⠀⠀⠀⠀⠀⠀\0", + "\x01⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡜\x02⢿⣿⣟⠀⠀⠀\x01⢀⡄⠀⠀⠀\0", + "\x01⠀⠀⠀⠉⠉⠉⠉\x02⣩⣭⡭\x01⠉⠉⠉⠉⠉\x02⠈⢿⣿⣆⠀\x01⢠⣿⣿⠂⠀⠀\0", + "\x02⠀⠀⠀⠀⠀⠀⣼⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⢻⡟\x01⣡⣿⣿⠃⠀⠀⠀\0", + "\x02⢸⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\x01⣰⣿⣿⣿⣿⣿⣿⡇\0", + "\x02⠀⠀⠀⢠⣿⣿⢋\x01⣼⣧⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⡟⠀⠀⠀⠀⠀⠀\0", + "\x02⠀⠀⠠⣿⣿⠃⠀\x01⠹⣿⣷⡀\x02⣀⣀⣀⣀⣀\x01⣚⣛⣋\x02⣀⣀⣀⣀⠀⠀⠀\0", + "\x02⠀⠀⠀⠘⠁⠀⠀⠀\x01⣽⣿⣷⡜\x02⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀\0", + "\x01⠀⠀⠀⠀⠀⠀⢀⣾⣿⠟⣿⣿⡄⠀⠀⠀\x02⠹⣿⣷⡀⠀⠀⠀⠀⠀⠀\0", + "\x01⠀⠀⠀⠀⠀⠀⢺⣿⠋⠀⠈⢿⣿⣆⠀⠀⠀\x02⠙⣿⡗⠀⠀⠀⠀⠀⠀", +) +.as_bytes(); /// Write one row from a packed color-marked byte stream. #[inline(never)] fn write_styled_row( - w: &mut StackWriter, - c: &colors::Colors, + writer: &mut StackWriter, + colors: &colors::Colors, stream: &mut &[u8], ) { - let colors = [c.blue, c.cyan, c.reset]; + let palette = [colors.blue, colors.cyan, colors.reset]; let data = *stream; - let row_end = data.iter().position(|&b| b == 0).unwrap_or(data.len()); + let row_end = data + .iter() + .position(|&byte| byte == 0) + .unwrap_or(data.len()); let row_data = &data[..row_end]; *stream = data.get(row_end + 1..).unwrap_or(&[]); - let mut i = 0; - while i < row_data.len() { - if let marker @ 1..=3 = row_data[i] { - w.push_str(colors[(marker - 1) as usize]); - i += 1; + let mut pos = 0; + while pos < row_data.len() { + if let marker @ 1..=3 = row_data[pos] { + writer.push_str(palette[usize::from(marker - 1)]); + pos += 1; } else { - let chunk_start = i; - while i < row_data.len() && row_data[i] > 3 { - i += 1; + let chunk_start = pos; + while pos < row_data.len() && row_data[pos] > 3 { + pos += 1; } - w.push_bytes(&row_data[chunk_start..i]); + writer.push_bytes(&row_data[chunk_start..pos]); } } } @@ -329,64 +330,52 @@ const ROW_LABELS: &[u8] = concat!( /// Write one row: logo + label + value. #[inline(never)] -#[allow(clippy::ref_option)] fn write_row( - w: &mut StackWriter, - c: &colors::Colors, + writer: &mut StackWriter, + colors: &colors::Colors, row: usize, custom_logo: Option<&str>, logo: &mut &[u8], labels: &mut &[u8], utsname: &UtsName, ) { - w.push_str(" "); - if let Some(custom_logo) = custom_logo { - w.push_str(c.cyan); - w.push_str(custom_logo); - w.push_str(c.reset); + writer.push_str(" "); + if let Some(logo_text) = custom_logo { + writer.push_str(colors.cyan); + writer.push_str(logo_text); } else { - write_styled_row(w, c, logo); - w.push_str(c.reset); + write_styled_row(writer, colors, logo); } - w.push_str(" "); + writer.push_str(colors.reset); + writer.push_str(" "); if row != 0 { - write_styled_row(w, c, labels); + write_styled_row(writer, colors, labels); } match row { 0 => { - system::write_username_and_hostname(w, c, utsname); - w.push_str(" ~"); - w.push_str(c.reset); - }, - 1 => { - let _ = release::write_os_pretty_name(w); + system::write_username_and_hostname(writer, colors, utsname); + writer.push_str(" ~"); + writer.push_str(colors.reset); }, - 2 => release::write_system_info(w, utsname), - 3 => cpu::write_cpu_name(w), - 4 => { - let _ = cpu::write_cpu_cores(w); - }, - 5 => system::write_shell(w), - 6 => { - let _ = uptime::write_uptime(w); - }, - 7 => desktop::write_desktop_info(w), - 8 => { - let _ = system::write_memory_usage(w, c); - }, - 9 => { - let _ = system::write_root_disk_usage(w, c); - }, - _ => colors::write_dots(w, c), + 1 => release::write_os_pretty_name(writer), + 2 => release::write_system_info(writer, utsname), + 3 => cpu::write_cpu_name(writer), + 4 => cpu::write_cpu_cores(writer), + 5 => system::write_shell(writer), + 6 => uptime::write(writer), + 7 => desktop::write_desktop_info(writer), + 8 => system::write_memory_usage(writer, colors), + 9 => system::write_root_disk_usage(writer, colors), + _ => colors::write_dots(writer, colors), } - w.push_byte(b'\n'); + writer.push_byte(b'\n'); } /// Print version information using direct syscall. fn print_version() { const VERSION: &str = concat!("Microfetch ", env!("CARGO_PKG_VERSION"), "\n"); unsafe { - let _ = sys_write(1, VERSION.as_ptr(), VERSION.len()); + _ = sys_write(1, VERSION.as_ptr(), VERSION.len()); } } @@ -397,7 +386,7 @@ fn print_version() { /// This function must be called with valid argc and argv from the program entry /// point. unsafe fn check_version_flag(argc: i32, argv: *const *const u8) -> bool { - if argc < 2 { + if argc < 2_i32 { return false; } // SAFETY: argv is a valid array of argc pointers @@ -407,10 +396,10 @@ unsafe fn check_version_flag(argc: i32, argv: *const *const u8) -> bool { } // Check if arg1 is "--version" let version_flag = b"--version\0"; - for (i, &b) in version_flag.iter().enumerate() { + for (flag_index, &flag_byte) in version_flag.iter().enumerate() { // SAFETY: arg1 is a valid C string - let arg_byte = unsafe { *arg1.add(i) }; - if arg_byte != b { + let arg_byte = unsafe { *arg1.add(flag_index) }; + if arg_byte != flag_byte { return false; } } @@ -427,7 +416,7 @@ unsafe fn check_version_flag(argc: i32, argv: *const *const u8) -> bool { /// /// # Errors /// -/// Returns an error if any system call fails +/// Returns an error if any system call fails. /// /// # Safety /// @@ -441,51 +430,51 @@ pub unsafe fn run(argc: i32, argv: *const *const u8) -> Result<(), Error> { let utsname = UtsName::uname()?; let no_color = colors::is_no_color(); - let c = colors::Colors::new(no_color); + let colors = colors::Colors::new(no_color); let mut buf = [MaybeUninit::uninit(); 2560]; - let mut w = StackWriter::new(&mut buf); + let mut writer = StackWriter::new(&mut buf); // Custom logo is 11 lines from MICROFETCH_LOGO env var, one per info row. // Lines beyond 11 are ignored; missing lines render as empty. - let custom_lines: [&str; 11]; + let custom_lines: [&str; ROW_COUNT]; let use_custom = !CUSTOM_LOGO.is_empty(); let logo_lines = if use_custom { let mut lines_iter = CUSTOM_LOGO.split('\n'); - custom_lines = core::array::from_fn(|_| lines_iter.next().unwrap_or("")); + custom_lines = array::from_fn(|_| lines_iter.next().unwrap_or("")); &custom_lines } else { - &[""; 11] // unused, we use LOGO pairs below + &[""; ROW_COUNT] // unused, we use LOGO pairs below }; let mut logo = LOGO; let mut labels = ROW_LABELS; - w.push_byte(b'\n'); + writer.push_byte(b'\n'); - for row in 0..ROW_COUNT { + for (row, &line) in logo_lines.iter().enumerate() { write_row( - &mut w, - &c, + &mut writer, + &colors, row, - use_custom.then_some(logo_lines[row]), + use_custom.then_some(line), &mut logo, &mut labels, &utsname, ); } - w.push_byte(b'\n'); + writer.push_byte(b'\n'); // Single syscall for the entire output. - let out = w.written(); + let out = writer.written(); let written = unsafe { sys_write(1, out.as_ptr(), out.len()) }; - if written < 0 { - #[allow(clippy::cast_possible_truncation)] - return Err(Error::OsError(written as i32)); - } + let Ok(count) = usize::try_from(written) else { + return Err( + i32::try_from(written).map_or(Error::WriteError, Error::OsError), + ); + }; - #[allow(clippy::cast_sign_loss)] - if written as usize != out.len() { + if count != out.len() { return Err(Error::WriteError); } diff --git a/crates/lib/src/release.rs b/crates/lib/src/release.rs index cdcef26..eb87b65 100644 --- a/crates/lib/src/release.rs +++ b/crates/lib/src/release.rs @@ -1,56 +1,52 @@ +#[cfg(target_os = "macos")] use core::str; + #[cfg(target_os = "linux")] -use crate::syscall::read_file_fast; -use crate::{Error, StackWriter, UtsName}; +use microfetch_asm::read_file_fast; + +use crate::{StackWriter, UtsName}; #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_system_info(w: &mut StackWriter, utsname: &UtsName) { - w.push_cstr(utsname.sysname()); - w.push_byte(b' '); - w.push_cstr(utsname.release()); - w.push_str(" ("); - w.push_cstr(utsname.machine()); - w.push_byte(b')'); +pub fn write_system_info(writer: &mut StackWriter, utsname: &UtsName) { + writer.push_cstr(utsname.sysname()); + writer.push_byte(b' '); + writer.push_cstr(utsname.release()); + writer.push_str(" ("); + writer.push_cstr(utsname.machine()); + writer.push_byte(b')'); } /// Writes the OS name from `kern.osproductversion` (macOS), e.g. `macOS 14.5`. -/// -/// # Errors -/// -/// Never errors; falls back to `macOS` if the version sysctl is unavailable. +/// Falls back to `macOS` if the version sysctl is unavailable. #[cfg(target_os = "macos")] #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_os_pretty_name(w: &mut StackWriter) -> Result<(), Error> { - w.push_str("macOS"); - let mut buf = [0u8; 64]; - if let Some(n) = - crate::syscall::macos_sysctl_str(b"kern.osproductversion\0", &mut buf) +pub fn write_os_pretty_name(writer: &mut StackWriter) { + use microfetch_asm::darwin::macos_sysctl_str; + + writer.push_str("macOS"); + let mut buf = [0_u8; 64]; + if let Some(len) = macos_sysctl_str(b"kern.osproductversion\0", &mut buf) + && let Ok(version) = str::from_utf8(&buf[..len]) + && !version.is_empty() { - if let Ok(version) = core::str::from_utf8(&buf[..n]) { - if !version.is_empty() { - w.push_byte(b' '); - w.push_str(version); - } - } + writer.push_byte(b' '); + writer.push_str(version); } - Ok(()) } -/// Writes the pretty name of the OS from `/etc/os-release`. -/// -/// # Errors -/// -/// Returns an error if `/etc/os-release` cannot be read. +/// Writes the pretty name of the OS from `/etc/os-release`, or nothing if it +/// cannot be read. #[cfg(target_os = "linux")] #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_os_pretty_name(w: &mut StackWriter) -> Result<(), Error> { +pub fn write_os_pretty_name(writer: &mut StackWriter) { // Fast byte-level scanning for PRETTY_NAME= const PREFIX: &[u8] = b"PRETTY_NAME="; - let mut buffer = [0u8; 1024]; + let mut buffer = [0_u8; 1024]; // Use fast syscall-based file reading - let bytes_read = read_file_fast("/etc/os-release", &mut buffer) - .map_err(Error::from_raw_os_error)?; + let Ok(bytes_read) = read_file_fast("/etc/os-release", &mut buffer) else { + return; + }; let content = &buffer[..bytes_read]; let mut offset = 0; @@ -60,7 +56,7 @@ pub fn write_os_pretty_name(w: &mut StackWriter) -> Result<(), Error> { // Find newline or end let line_end = remaining .iter() - .position(|&b| b == b'\n') + .position(|&byte| byte == b'\n') .unwrap_or(remaining.len()); let line = &remaining[..line_end]; @@ -80,13 +76,12 @@ pub fn write_os_pretty_name(w: &mut StackWriter) -> Result<(), Error> { // Write bytes directly — os-release values are effectively always // valid UTF-8 (ASCII names, version numbers). No lossy conversion // needed. - w.push_bytes(trimmed); - return Ok(()); + writer.push_bytes(trimmed); + return; } offset += line_end + 1; } - w.push_str("Unknown"); - Ok(()) + writer.push_str("Unknown"); } diff --git a/crates/lib/src/system.rs b/crates/lib/src/system.rs index 6bf431d..19c2e13 100644 --- a/crates/lib/src/system.rs +++ b/crates/lib/src/system.rs @@ -1,111 +1,94 @@ use core::mem::MaybeUninit; #[cfg(target_os = "linux")] -use crate::syscall::read_file_fast; -use crate::{ - Error, - StackWriter, - UtsName, - colors::Colors, - syscall::{StatfsBuf, sys_statfs}, -}; +use microfetch_asm::read_file_fast; +use microfetch_asm::{StatfsBuf, sys_statfs}; + +use crate::{StackWriter, UtsName, colors::Colors}; #[cfg_attr(feature = "hotpath", hotpath::measure)] pub fn write_username_and_hostname( - w: &mut StackWriter, + writer: &mut StackWriter, colors: &Colors, utsname: &UtsName, ) { let username = crate::getenv_str("USER").unwrap_or("unknown_user"); let hostname = utsname.nodename(); - w.push_str(colors.yellow); - w.push_str(username); - w.push_str(colors.red); - w.push_byte(b'@'); - w.push_str(colors.green); - w.push_cstr(hostname); - w.push_str(colors.reset); + writer.push_str(colors.yellow); + writer.push_str(username); + writer.push_str(colors.red); + writer.push_byte(b'@'); + writer.push_str(colors.green); + writer.push_cstr(hostname); + writer.push_str(colors.reset); } #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_shell(w: &mut StackWriter) { +pub fn write_shell(writer: &mut StackWriter) { let shell = crate::getenv_str("SHELL").unwrap_or(""); if shell.is_empty() { - w.push_str("unknown_shell"); + writer.push_str("unknown_shell"); } else { - let start = shell.rfind('/').map_or(0, |i| i + 1); - w.push_str(&shell[start..]); + writer.push_str(shell.rsplit_once('/').map_or(shell, |(_, name)| name)); } } -/// Gets the root disk usage information. -/// -/// # Errors -/// -/// Returns an error if the filesystem information cannot be retrieved. +/// Writes the root disk usage, or nothing if the filesystem information cannot +/// be retrieved. #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_root_disk_usage( - w: &mut StackWriter, - colors: &Colors, -) -> Result<(), Error> { - let mut vfs = MaybeUninit::::uninit(); +pub fn write_root_disk_usage(writer: &mut StackWriter, colors: &Colors) { + let mut vfs_buf = MaybeUninit::::uninit(); let path = b"/\0"; - if unsafe { sys_statfs(path.as_ptr(), vfs.as_mut_ptr()) } != 0 { - return Err(Error::last_os_error()); + if unsafe { sys_statfs(path.as_ptr(), vfs_buf.as_mut_ptr()) } != 0_i32 { + return; } - let vfs = unsafe { vfs.assume_init() }; - #[allow(clippy::cast_sign_loss)] - let block_size = vfs.f_bsize as u64; + let vfs = unsafe { vfs_buf.assume_init() }; + let block_size = vfs.block_size(); + let total_blocks = vfs.f_blocks; let available_blocks = vfs.f_bavail; let total_bytes = block_size * total_blocks; let used_bytes = total_bytes - (block_size * available_blocks); - write_gib(w, used_bytes); - w.push_str(" GiB / "); - write_gib(w, total_bytes); - w.push_str(" GiB ("); - w.push_str(colors.cyan); - let pct = if total_bytes > 0 { - used_bytes * 100 / total_bytes - } else { - 0 - }; - w.push_u64(pct); - w.push_byte(b'%'); - w.push_str(colors.reset); - w.push_byte(b')'); - - Ok(()) + write_gib(writer, used_bytes); + writer.push_str(" GiB / "); + write_gib(writer, total_bytes); + writer.push_str(" GiB ("); + writer.push_str(colors.cyan); + let pct = (used_bytes * 100).checked_div(total_bytes).unwrap_or(0); + writer.push_u64(pct); + writer.push_byte(b'%'); + writer.push_str(colors.reset); + writer.push_byte(b')'); } -fn write_centi_gib(w: &mut StackWriter, centi_gib: u64) { - w.push_u64(centi_gib / 100); - w.push_byte(b'.'); - let frac = (centi_gib % 100) as u8; - w.push_byte(b'0' + frac / 10); - w.push_byte(b'0' + frac % 10); +fn write_centi_gib(writer: &mut StackWriter, centi_gib: u64) { + writer.push_u64(centi_gib / 100); + writer.push_byte(b'.'); + let frac = u8::try_from(centi_gib % 100).unwrap_or(0); + writer.push_byte(b'0' + frac / 10); + writer.push_byte(b'0' + frac % 10); } -fn write_gib(w: &mut StackWriter, bytes: u64) { - write_centi_gib(w, (bytes * 100 + (1 << 29)) >> 30); +fn write_gib(writer: &mut StackWriter, bytes: u64) { + write_centi_gib(writer, (bytes * 100 + (1 << 29)) >> 30); } #[cfg(target_os = "linux")] -fn write_kb_as_gib(w: &mut StackWriter, kb: u64) { - write_centi_gib(w, (kb * 100 + (1 << 19)) >> 20); +fn write_kb_as_gib(writer: &mut StackWriter, kb: u64) { + write_centi_gib(writer, (kb * 100 + (1 << 19)) >> 20); } -/// Fast integer parsing without stdlib overhead +/// Fast integer parsing without stdlib overhead. #[cfg(target_os = "linux")] #[inline] -fn parse_u64_fast(s: &[u8]) -> u64 { - let mut result = 0u64; - for &byte in s { +fn parse_u64_fast(bytes: &[u8]) -> u64 { + let mut result = 0_u64; + for &byte in bytes { if byte.is_ascii_digit() { result = result * 10 + u64::from(byte - b'0'); } else { @@ -116,57 +99,43 @@ fn parse_u64_fast(s: &[u8]) -> u64 { } /// Writes the system memory usage information via `sysctl`/Mach (macOS). -/// -/// # Errors -/// -/// Returns an error if the memory statistics cannot be retrieved. +/// Writes nothing if the memory statistics cannot be retrieved. #[cfg(target_os = "macos")] #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_memory_usage( - w: &mut StackWriter, - colors: &Colors, -) -> Result<(), Error> { - let (used_bytes, total_bytes) = - crate::syscall::macos_meminfo().ok_or(Error::OsError(0))?; - let percentage_used = if total_bytes > 0 { - (used_bytes * 100 + total_bytes / 2) / total_bytes - } else { - 0 - }; +pub fn write_memory_usage(writer: &mut StackWriter, colors: &Colors) { + use microfetch_asm::darwin::macos_meminfo; - write_gib(w, used_bytes); - w.push_str(" GiB / "); - write_gib(w, total_bytes); - w.push_str(" GiB ("); - w.push_str(colors.cyan); - w.push_u64(percentage_used); - w.push_byte(b'%'); - w.push_str(colors.reset); - w.push_byte(b')'); - - Ok(()) + let Some((used_bytes, total_bytes)) = macos_meminfo() else { + return; + }; + let percentage_used = (used_bytes * 100 + total_bytes / 2) + .checked_div(total_bytes) + .unwrap_or(0); + + write_gib(writer, used_bytes); + writer.push_str(" GiB / "); + write_gib(writer, total_bytes); + writer.push_str(" GiB ("); + writer.push_str(colors.cyan); + writer.push_u64(percentage_used); + writer.push_byte(b'%'); + writer.push_str(colors.reset); + writer.push_byte(b')'); } /// Gets the system memory usage information. -/// -/// # Errors -/// -/// Returns an error if `/proc/meminfo` cannot be read. +/// Writes nothing if `/proc/meminfo` cannot be read. #[cfg(target_os = "linux")] #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_memory_usage( - w: &mut StackWriter, - colors: &Colors, -) -> Result<(), Error> { +pub fn write_memory_usage(writer: &mut StackWriter, colors: &Colors) { #[cfg_attr(feature = "hotpath", hotpath::measure)] - fn parse_memory_info() -> Result<(u64, u64), Error> { - let mut total_memory_kb = 0u64; - let mut available_memory_kb = 0u64; - let mut buffer = [0u8; 1024]; + fn parse_memory_info() -> Option<(u64, u64)> { + let mut total_memory_kb = 0_u64; + let mut available_memory_kb = 0_u64; + let mut buffer = [0_u8; 1024]; // Use fast syscall-based file reading - let bytes_read = read_file_fast("/proc/meminfo", &mut buffer) - .map_err(Error::from_raw_os_error)?; + let bytes_read = read_file_fast("/proc/meminfo", &mut buffer).ok()?; let meminfo = &buffer[..bytes_read]; // Fast scanning for MemTotal and MemAvailable @@ -180,50 +149,39 @@ pub fn write_memory_usage( // Find newline or end let line_end = remaining .iter() - .position(|&b| b == b'\n') + .position(|&byte| byte == b'\n') .unwrap_or(remaining.len()); let line = &remaining[..line_end]; - if line.starts_with(b"MemTotal:") { - // Skip "MemTotal:" and whitespace - let mut pos = 9; - while pos < line.len() && line[pos].is_ascii_whitespace() { - pos += 1; - } - total_memory_kb = parse_u64_fast(&line[pos..]); + if let Some(value) = line.strip_prefix(b"MemTotal:") { + total_memory_kb = parse_u64_fast(value.trim_ascii_start()); found_total = true; - } else if line.starts_with(b"MemAvailable:") { - // Skip "MemAvailable:" and whitespace - let mut pos = 13; - while pos < line.len() && line[pos].is_ascii_whitespace() { - pos += 1; - } - available_memory_kb = parse_u64_fast(&line[pos..]); + } + if let Some(value) = line.strip_prefix(b"MemAvailable:") { + available_memory_kb = parse_u64_fast(value.trim_ascii_start()); found_available = true; } offset += line_end + 1; } - Ok((total_memory_kb - available_memory_kb, total_memory_kb)) + Some((total_memory_kb - available_memory_kb, total_memory_kb)) } - let (used_kb, total_kb) = parse_memory_info()?; - let percentage_used = if total_kb > 0 { - (used_kb * 100 + total_kb / 2) / total_kb - } else { - 0 + let Some((used_kb, total_kb)) = parse_memory_info() else { + return; }; - - write_kb_as_gib(w, used_kb); - w.push_str(" GiB / "); - write_kb_as_gib(w, total_kb); - w.push_str(" GiB ("); - w.push_str(colors.cyan); - w.push_u64(percentage_used); - w.push_byte(b'%'); - w.push_str(colors.reset); - w.push_byte(b')'); - - Ok(()) + let percentage_used = (used_kb * 100 + total_kb / 2) + .checked_div(total_kb) + .unwrap_or(0); + + write_kb_as_gib(writer, used_kb); + writer.push_str(" GiB / "); + write_kb_as_gib(writer, total_kb); + writer.push_str(" GiB ("); + writer.push_str(colors.cyan); + writer.push_u64(percentage_used); + writer.push_byte(b'%'); + writer.push_str(colors.reset); + writer.push_byte(b')'); } diff --git a/crates/lib/src/uptime.rs b/crates/lib/src/uptime.rs index 55ced5f..3f3fce0 100644 --- a/crates/lib/src/uptime.rs +++ b/crates/lib/src/uptime.rs @@ -1,59 +1,57 @@ #[cfg(target_os = "linux")] use core::mem::MaybeUninit; -#[cfg(target_os = "linux")] use crate::syscall::sys_sysinfo; -use crate::{Error, StackWriter}; +#[cfg(target_os = "macos")] +use microfetch_asm::darwin::macos_uptime_secs; +#[cfg(target_os = "linux")] use microfetch_asm::sys_sysinfo; -/// Gets the current system uptime. -/// -/// # Errors -/// -/// Returns an error if the system uptime cannot be retrieved. +use crate::StackWriter; + +/// Writes the current system uptime, or nothing if it cannot be retrieved. #[cfg_attr(feature = "hotpath", hotpath::measure)] -pub fn write_uptime(w: &mut StackWriter) -> Result<(), Error> { +pub fn write(writer: &mut StackWriter) { #[cfg(target_os = "linux")] let uptime_seconds = { let mut info = MaybeUninit::uninit(); if unsafe { sys_sysinfo(info.as_mut_ptr()) } != 0 { - return Err(Error::last_os_error()); - } - #[allow(clippy::cast_sign_loss)] - unsafe { - info.assume_init().uptime as u64 + return; } + let Ok(seconds) = u64::try_from(unsafe { info.assume_init() }.uptime) + else { + return; + }; + seconds }; #[cfg(target_os = "macos")] - let uptime_seconds = - crate::syscall::macos_uptime_secs().ok_or(Error::OsError(0))?; + let Some(uptime_seconds) = macos_uptime_secs() else { + return; + }; let days = uptime_seconds / 86400; let hours = (uptime_seconds / 3600) % 24; let minutes = (uptime_seconds / 60) % 60; - let mut any = false; + let mut any = days > 0; - if days > 0 { - w.push_u64(days); - w.push_str(if days == 1 { " day" } else { " days" }); - any = true; + if any { + writer.push_u64(days); + writer.push_str(if days == 1 { " day" } else { " days" }); } if hours > 0 { if any { - w.push_str(", "); + writer.push_str(", "); } - w.push_u64(hours); - w.push_str(if hours == 1 { " hour" } else { " hours" }); + writer.push_u64(hours); + writer.push_str(if hours == 1 { " hour" } else { " hours" }); any = true; } if minutes > 0 { if any { - w.push_str(", "); + writer.push_str(", "); } - w.push_u64(minutes); - w.push_str(if minutes == 1 { " minute" } else { " minutes" }); + writer.push_u64(minutes); + writer.push_str(if minutes == 1 { " minute" } else { " minutes" }); any = true; } if !any { - w.push_str("less than a minute"); + writer.push_str("less than a minute"); } - - Ok(()) } diff --git a/hotpath/policy.toml b/hotpath/policy.toml index d084a0a..745d638 100644 --- a/hotpath/policy.toml +++ b/hotpath/policy.toml @@ -6,13 +6,13 @@ min_percent_total = 2 [functions.alloc] -judged = true +judged = true +metrics = [ "avg", "total" ] +min_calls = 1 min_percent_change = 20 -metrics = ["avg", "total"] -min_calls = 1 [functions.timing] -judged = false +judged = false +metrics = [ "avg", "total" ] +min_calls = 1 min_percent_change = 50 -metrics = ["avg", "total"] -min_calls = 1 diff --git a/microfetch/Cargo.toml b/microfetch/Cargo.toml index 5d0bfee..329dfd2 100644 --- a/microfetch/Cargo.toml +++ b/microfetch/Cargo.toml @@ -10,12 +10,12 @@ repository = "https://github.com/notashelf/microfetch" publish = true [[bin]] -name = "microfetch" -test = false +name = "microfetch" +test = false [dependencies] -microfetch-asm.workspace = true -microfetch-lib.workspace = true +microfetch-asm.workspace = true +microfetch-lib.workspace = true [lints] workspace = true diff --git a/microfetch/build.rs b/microfetch/build.rs index fb2811e..16f5620 100644 --- a/microfetch/build.rs +++ b/microfetch/build.rs @@ -1,11 +1,8 @@ -use std::{env, process::Command}; +use std::{env, io, process::Command}; -fn main() { +fn main() -> io::Result<()> { let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); - let version = Command::new(rustc) - .arg("-vV") - .output() - .expect("failed to run `rustc -vV`"); + let version = Command::new(rustc).arg("-vV").output()?; let nightly = String::from_utf8_lossy(&version.stdout) .lines() .any(|line| { @@ -24,9 +21,9 @@ fn main() { // macOS cannot link statically, requires the standard C runtime startup, and // uses Mach-O (not ELF), so none of the flags below apply. The default // linker driver produces a correct (and ad-hoc code-signed) binary there. - let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); if target_os == "macos" { - return; + return Ok(()); } // No C runtime, we provide _start ourselves @@ -40,11 +37,13 @@ fn main() { // Remove unreferenced input sections println!("cargo:rustc-link-arg-bin=microfetch=-Wl,--gc-sections"); // Strip all symbol table entries - if std::env::var("DEBUG").as_deref() != Ok("true") { + if env::var("DEBUG").as_deref() != Ok("true") { println!("cargo:rustc-link-arg-bin=microfetch=-Wl,--strip-all"); } // Omit the .note.gnu.build-id section println!("cargo:rustc-link-arg-bin=microfetch=-Wl,--build-id=none"); // Disable RELRO (removes relro_padding) println!("cargo:rustc-link-arg-bin=microfetch=-Wl,-z,norelro"); + + Ok(()) } diff --git a/microfetch/src/main.rs b/microfetch/src/main.rs index f6f9ffa..84d6cdf 100644 --- a/microfetch/src/main.rs +++ b/microfetch/src/main.rs @@ -9,18 +9,26 @@ ), feature(asm_experimental_arch) )] -#![cfg_attr(nightly, feature(lang_items))] +#![cfg_attr( + nightly, + feature(lang_items), + expect( + internal_features, + reason = "only the lang item can name the personality routine" + ) +)] -#[cfg(not(target_os = "macos"))] use core::arch::naked_asm; +#[cfg(all(target_arch = "powerpc64", target_abi = "elfv1"))] +use core::arch::global_asm; +#[cfg(not(any(target_os = "macos", target_abi = "elfv1")))] +use core::arch::naked_asm; +#[cfg(not(test))] use core::panic::PanicInfo; +#[cfg(all(not(test), target_arch = "sparc"))] use core::ptr; // The custom `_start` (and the `entry_rust` it calls) is Linux-only. -#[cfg(not(target_os = "macos"))] +#[cfg(not(any(target_os = "macos", target_abi = "elfv1")))] use microfetch_asm::entry_rust; use microfetch_asm::sys_write; -// Re-export libc replacement functions from asm crate. On macOS these are -// provided by libSystem, so we don't define (or re-export) our own. -#[cfg(not(target_os = "macos"))] -pub use microfetch_asm::{memcpy, memset, strlen}; #[cfg(target_arch = "x86_64")] #[unsafe(no_mangle)] @@ -163,7 +171,7 @@ unsafe extern "C" fn _start() { // in .opd whose first word is the real code address. We emit both manually via // `global_asm` so the kernel reads the descriptor and jumps into `_start_impl`. #[cfg(all(target_arch = "powerpc64", target_abi = "elfv1"))] -core::arch::global_asm!( +global_asm!( ".section .opd, \"aw\"", ".balign 8", ".globl _start", @@ -239,7 +247,7 @@ unsafe extern "C" fn _start() { #[cfg(target_arch = "mips64")] #[unsafe(no_mangle)] #[unsafe(naked)] -unsafe extern "C" fn _start() { +unsafe extern "C" fn __start() { naked_asm!( "move $a0, $sp", // first arg = original sp (argc/argv) "daddiu $sp, $sp, -16",// reserve + keep 16-byte alignment (N64 ABI) @@ -275,19 +283,19 @@ unsafe extern "C" fn _start() { #[cfg(all(not(test), target_arch = "sparc"))] #[unsafe(no_mangle)] extern "C" fn __atomic_load_1(ptr: *const u8, _order: i32) -> u8 { - unsafe { core::ptr::read_volatile(ptr) } + unsafe { ptr::read_volatile(ptr) } } #[cfg(all(not(test), target_arch = "sparc"))] #[unsafe(no_mangle)] extern "C" fn __atomic_store_1(ptr: *mut u8, val: u8, _order: i32) { - unsafe { core::ptr::write_volatile(ptr, val) } + unsafe { ptr::write_volatile(ptr, val) } } #[cfg(target_arch = "mips")] #[unsafe(no_mangle)] #[unsafe(naked)] -unsafe extern "C" fn _start() { +unsafe extern "C" fn __start() { naked_asm!( "move $a0, $sp", // first arg = original sp (argc/argv) "addiu $sp, $sp, -24", // reserve 16-byte O32 shadow space + align @@ -316,33 +324,32 @@ pub unsafe extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 { // Initialize the environment pointer unsafe { microfetch_lib::init_env(envp); - } + }; // Run the main application logic - match unsafe { microfetch_lib::run(argc, argv) } { - Ok(()) => 0, - Err(_) => { - const ERR_MSG: &[u8] = b"Error\n"; - let _ = unsafe { sys_write(2, ERR_MSG.as_ptr(), ERR_MSG.len()) }; - 1 - }, + if unsafe { microfetch_lib::run(argc, argv) }.is_ok() { + 0 + } else { + const ERR_MSG: &[u8] = b"Error\n"; + _ = unsafe { sys_write(2, ERR_MSG.as_ptr(), ERR_MSG.len()) }; + 1 } } #[cfg(not(test))] #[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { +fn panic(_info: &PanicInfo) -> ! { const PANIC_MSG: &[u8] = b"panic\n"; unsafe { - let _ = sys_write(2, PANIC_MSG.as_ptr(), PANIC_MSG.len()); + _ = sys_write(2, PANIC_MSG.as_ptr(), PANIC_MSG.len()); microfetch_asm::sys_exit(1) } } -/// Stubs for Rust exception handling +/// Stubs for Rust exception handling. /// /// Nightly mangles this symbol with a per-compiler hash since -/// https://github.com/rust-lang/rust/pull/148413, so only the lang item can name +/// , so only the lang item can name /// it there. #[cfg(all(not(test), nightly))] #[lang = "eh_personality"]