Skip to content

luytan/cardwire

Repository files navigation

cardwire

AUR GitHub License

A GPU manager for Linux using eBPF LSM hooks to block GPUs

Disclaimer

  • This project is in early development. Expect bugs and incomplete functionality
  • The Makefile was AI-generated, i only use the flake.nix, be careful

Requirements

  • Linux Kernel: version 5.7 or later
  • eBPF LSM: Your kernel must have CONFIG_BPF_LSM=y, and you must enable LSM on your system

Quick Start

Arch:

yay -S cardwire

Nix with flakes:

flake.nix:

    cardwire = {
      url = "github:luytan/cardwire";
      inputs.nixpkgs.follows = "nixpkgs";
    };

then import:

  imports = [
    inputs.cardwire.nixosModules.default
  ];
  services.cardwire.enable = true;

Usage

The cardwire CLI lets you manage GPU states and system modes

Modes

  • Integrated: Blocks the discrete GPU
  • Hybrid: Unblocks the discrete GPU
  • Manual: Default mode for safety, allows individual GPU blocking/unblocking

Note: Integrated/Hybrid modes only work on host with two GPUs

Note 2: Manual mode is not implemented

# Set system mode
cardwire set integrated / hybrid / manual

# Get current mode status
cardwire get

# List all detected GPUs and their status
cardwire list

# Manually block/unblock a specific GPU by ID
cardwire gpu 1 --block
cardwire gpu 1 --unblock

Configuration

The daemon reads its configuration from /var/lib/cardwire/cardwire.toml. If the file is missing, it defaults to Manual mode.

# /var/lib/cardwire/cardwire.toml
mode = "Manual"
block_vulkan = false

block_vulkan is an experimental feature that blocks the nvidia's vulkan icd, must be used with caution

Building and Development

Using Nix

# Enter development shell
nix develop

# Build the project
nix build

# Run formatting checks
nix build .#checks.x86_64-linux.pre-commit-check

# Run integration tests in VM
nix build .#checks.x86_64-linux.vm-test

# Build the vm and enter
nix run .#nixosConfigurations.x86_64-linux.config.system.build.vm

Manual Compilation

If you don't use Nix, ensure you have clang, libbpf and cargo installed (needed for eBPF compilation during the Rust build)

# Build the project
make

# Install binaries, systemd service, and D-Bus config (requires sudo)
sudo make install

How it works

Cardwire uses eBPF with LSM hooks to intercept file operations on GPU device nodes, such as /dev/dri/renderDX, /dev/dri/cardX, sysfs config and nvidiaX

When a GPU is "blocked," the eBPF program returns -ENOENT for any syscall targeting that device. This provides several key benefits:

  • Instant App Startup: Prevents applications (like Electron apps or GTK apps) from attempting to initialize the GPU, this eliminates the 3–4 second "hang" typically caused by waiting for a sleeping GPU to power up
  • Power Efficiency: By blocking access at the syscall level, the GPU is never woken from its lowest power state (D3cold), extending battery life on laptops
  • Non-Invasive: Unlike traditional methods that might require driver unloading, risky unbind or complex X11/Wayland setups, this approach is transparent to the rest of the system and easy to toggle
  • Also works with games

Project Structure

  • crates/cardwire-cli: User CLI to interact with the daemon
  • crates/cardwire-core: Low-level GPU manager and IOMMU discovery
  • crates/cardwire-daemon: System daemon managing state and D-Bus communication
  • crates/cardwire-ebpf: BPF program and LSM hooks

Notes

  • I'm still learning Rust, if some parts of the code are bad or unoptimized, feel free to open a PR

Credits

  • Asus-linux Discord for helping me find the ebpf method
  • Caelestia shell for the flake.nix, i used it as a reference

License

This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.

About

A GPU Manager for linux that uses eBPF LSM hooks to block GPUs

Resources

License

Stars

Watchers

Forks

Packages