#!/bin/sh # Clawdie Shell — NVIDIA GPU Detection Module # Purpose: Detect NVIDIA GPU and select appropriate driver version # POSIX-compliant (no bash-isms) set -eu # Configuration (can be overridden for testing) RC_CONF="${RC_CONF:-/etc/rc.conf}" LOG_FILE="${LOG_FILE:-/var/log/clawdie-firstboot.log}" PROGRESS_FILE="${PROGRESS_FILE:-/var/log/clawdie-firstboot.progress}" # ============================================================================ # MAIN ENTRY POINT # ============================================================================ clawdie_shell_nvidia_detect() { # Main orchestrator: detect NVIDIA GPU and select driver version # Only runs if DETECTED_GPU=nvidia (called by firstboot.sh) # Sets NVIDIA_DRIVER to 590, 470, or 390 if [ "${DETECTED_GPU:-}" != "nvidia" ]; then log_msg "[nvidia] Not an NVIDIA GPU — skipping" return 0 fi log_msg "[nvidia] Detecting NVIDIA GPU type" # Query pciconf for NVIDIA device ID local device_id device_id=$(clawdie_shell_nvidia_get_device_id) || { log_msg "[nvidia] ERROR: Could not detect NVIDIA device ID" NVIDIA_DRIVER="590" echo "[NVIDIA] Default 590" >> "$PROGRESS_FILE" return 1 } log_msg "[nvidia] Device ID: $device_id" # Match device ID to driver version NVIDIA_DRIVER=$(clawdie_shell_nvidia_select_driver "$device_id") log_msg "[nvidia] Selected driver version: nvidia-driver-$NVIDIA_DRIVER" # Update rc.conf to include correct NVIDIA driver version clawdie_shell_nvidia_write_rcconf "$NVIDIA_DRIVER" # Install the NVIDIA driver package clawdie_shell_nvidia_install "$NVIDIA_DRIVER" echo "[NVIDIA] $NVIDIA_DRIVER" >> "$PROGRESS_FILE" log_msg "[nvidia] NVIDIA detection complete" } # ============================================================================ # NVIDIA DEVICE DETECTION # ============================================================================ clawdie_shell_nvidia_get_device_id() { # Query pciconf for NVIDIA GPU device ID # Returns: device ID in hex format (e.g., "2388") local pciconf_out local device_id pciconf_out=$(pciconf -lv 2>/dev/null | grep -i "class=0x030000.*NVIDIA" | head -1 || true) if [ -z "$pciconf_out" ]; then return 1 fi # Extract device ID from chip field (format: chip=0xVVDDxx) # where VV = vendor (10de for NVIDIA), DD = device ID, xx = revision device_id=$(echo "$pciconf_out" | grep -o "chip=0x10de[a-f0-9]*" | cut -c11-14 || true) if [ -z "$device_id" ]; then return 1 fi echo "$device_id" } # ============================================================================ # DRIVER VERSION SELECTION # ============================================================================ clawdie_shell_nvidia_select_driver() { # Map NVIDIA device ID to supported driver version # Input: device ID (hex, 4 chars) # Output: driver version (590, 470, or 390) # # Rough mapping (simplified for common GPUs): # - Maxwell (GTX 750, 750 Ti, GTX 950-980 Ti) → 470 (0x1340-0x2186) # - Kepler (GTX 650-780 Ti) → 390 (0x1180-0x139D) # - Turing/Ampere (RTX 2060+, RTX 30xx) → 590 (0x2060+) # - Ada (RTX 40xx) → 590 (0x2700+) local device_id="${1:-0000}" local device_num # Convert hex device ID to decimal for easier comparison device_num=$(printf "%d" "0x$device_id" 2>/dev/null || echo "0") # Turing and newer (RTX 20xx, 30xx, 40xx, etc.) — driver 590 # RTX 2060+ starts around 0x2060 (8288), RTX 30xx around 0x2200 (8704), RTX 40xx around 0x2700 (9984) if [ "$device_num" -ge 8288 ]; then echo "590" return 0 fi # Maxwell (GTX 750-980 Ti) — driver 470 # Range roughly 0x1340 (4928) to 0x2186 (8582) if [ "$device_num" -ge 4928 ] && [ "$device_num" -le 8582 ]; then echo "470" return 0 fi # Kepler and older (GTX 650-780 Ti) — driver 390 # Range roughly 0x1180 (4480) to 0x139F (5023) if [ "$device_num" -ge 4480 ] && [ "$device_num" -le 5100 ]; then echo "390" return 0 fi # Default: assume modern GPU → driver 590 echo "590" } # ============================================================================ # RC.CONF WRITING # ============================================================================ clawdie_shell_nvidia_write_rcconf() { # Write NVIDIA driver version to rc.conf # Input: driver version (590, 470, or 390) local nvidia_version="${1:-590}" local pkg_name="nvidia-driver-$nvidia_version" if [ ! -f "$RC_CONF" ]; then log_msg "[nvidia] Creating $RC_CONF" touch "$RC_CONF" fi # Remove existing NVIDIA references from kld_list if grep -q "^kld_list=" "$RC_CONF" 2>/dev/null; then # Remove nvidia and nvidia-modeset from existing kld_list local kld=$(grep "^kld_list=" "$RC_CONF" | cut -d= -f2 | tr -d '"') kld=$(echo "$kld" | sed 's/nvidia-modeset //g; s/nvidia //g; s/ / /g' | xargs) sed -i.bak '/^kld_list=/d' "$RC_CONF" rm -f "$RC_CONF.bak" # Re-add kld_list with NVIDIA driver if [ -n "$kld" ]; then echo "kld_list=\"nvidia-modeset nvidia $kld\"" >> "$RC_CONF" else echo "kld_list=\"nvidia-modeset nvidia\"" >> "$RC_CONF" fi else # No existing kld_list echo "kld_list=\"nvidia-modeset nvidia\"" >> "$RC_CONF" fi log_msg "[nvidia] Configured rc.conf for $pkg_name" } # ============================================================================ # PACKAGE INSTALLATION # ============================================================================ clawdie_shell_nvidia_install() { # Install NVIDIA driver package # Input: driver version (590, 470, or 390) local nvidia_version="${1:-590}" local pkg_name="nvidia-driver-$nvidia_version" # Check if already installed if pkg info "$pkg_name" >/dev/null 2>&1; then log_msg "[nvidia] $pkg_name already installed" return 0 fi log_msg "[nvidia] Installing $pkg_name..." # Try to install (works offline if packages on USB, online if network available) if pkg install -y "$pkg_name" >/dev/null 2>&1; then log_msg "[nvidia] Successfully installed $pkg_name" return 0 else log_msg "[nvidia] WARNING: Failed to install $pkg_name" log_msg "[nvidia] System may need network access or USB packages" return 1 fi } # ============================================================================ # VALIDATION # ============================================================================ clawdie_shell_nvidia_validate() { # Verify NVIDIA configuration in rc.conf if [ ! -f "$RC_CONF" ]; then log_msg "[nvidia] ERROR: $RC_CONF not found" return 1 fi if ! grep -q "nvidia" "$RC_CONF" 2>/dev/null; then log_msg "[nvidia] ERROR: NVIDIA not configured in rc.conf" return 1 fi return 0 } # ============================================================================ # LOGGING HELPER # ============================================================================ log_msg() { echo "$(date '+%H:%M:%S') $1" | tee -a "$LOG_FILE" 2>/dev/null || true } # Only run if sourced directly (not during test) if [ "${SHELL_NVIDIA_TEST:-0}" -eq 0 ]; then clawdie_shell_nvidia_detect fi