2026-05-24 23:21:02 +02:00
|
|
|
#!/bin/sh
|
|
|
|
|
# Clawdie operator USB live GPU setup.
|
|
|
|
|
# Detect display hardware and load a conservative KMS module before SDDM.
|
|
|
|
|
# Prefer integrated/open drivers so hybrid laptops boot the broadest path first;
|
|
|
|
|
# keep NVIDIA proprietary loading opt-in by requiring an installed nvidia.ko.
|
2026-06-04 21:30:38 +02:00
|
|
|
# Dedicated NVIDIA-target images can override that preference in rc.conf.
|
2026-05-24 23:21:02 +02:00
|
|
|
|
|
|
|
|
# PROVIDE: clawdie_live_gpu
|
|
|
|
|
# REQUIRE: FILESYSTEMS devfs
|
|
|
|
|
# BEFORE: sddm
|
|
|
|
|
# KEYWORD: nojail
|
|
|
|
|
|
|
|
|
|
. /etc/rc.subr
|
|
|
|
|
|
|
|
|
|
name="clawdie_live_gpu"
|
|
|
|
|
rcvar="clawdie_live_gpu_enable"
|
|
|
|
|
start_cmd="clawdie_live_gpu_start"
|
|
|
|
|
|
|
|
|
|
LOG_FILE="/var/log/clawdie-live-gpu.log"
|
|
|
|
|
|
|
|
|
|
clawdie_live_gpu_log()
|
|
|
|
|
{
|
|
|
|
|
echo "$(date '+%H:%M:%S') $*" >> "$LOG_FILE" 2>/dev/null || true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clawdie_live_gpu_display_blocks()
|
|
|
|
|
{
|
|
|
|
|
pciconf -lv 2>/dev/null | awk '
|
|
|
|
|
BEGIN { RS = ""; IGNORECASE = 1 }
|
|
|
|
|
/class=0x03/ { print }
|
|
|
|
|
'
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-04 21:30:38 +02:00
|
|
|
clawdie_live_gpu_nvidia_block()
|
|
|
|
|
{
|
|
|
|
|
echo "$1" | awk '
|
|
|
|
|
BEGIN { RS = ""; IGNORECASE = 1 }
|
|
|
|
|
/(^|[[:space:]])vendor=0x10de([[:space:]]|$)/ { print; exit }
|
|
|
|
|
'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clawdie_live_gpu_nvidia_device_id()
|
|
|
|
|
{
|
|
|
|
|
_block=$(clawdie_live_gpu_nvidia_block "$1")
|
|
|
|
|
[ -n "$_block" ] || return 1
|
|
|
|
|
|
2026-06-04 22:07:02 +02:00
|
|
|
# FreeBSD pciconf chip field is chip=0x<device><vendor>. NVIDIA's vendor id
|
|
|
|
|
# 0x10de sits in the LOW 16 bits, so the device id is the 4 hex digits BEFORE
|
|
|
|
|
# it (e.g. chip=0x1c8c10de -> device id 1c8c). The earlier "chip=0x10de..."
|
|
|
|
|
# form read the vendor half and never matched.
|
|
|
|
|
echo "$_block" | grep -Eo 'chip=0x[0-9a-fA-F]{4}10de' | head -1 |
|
|
|
|
|
sed 's/^chip=0x//; s/10de$//'
|
2026-06-04 21:30:38 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-04 22:07:02 +02:00
|
|
|
# Map an NVIDIA PCI device id (4 hex digits) to the recommended driver branch.
|
|
|
|
|
# Returns labels in the build's lane vocabulary {390, 470, 590} so the value can
|
|
|
|
|
# be compared directly with clawdie_live_gpu_nvidia_branch staged from build.sh.
|
|
|
|
|
# (The "590" lane installs the current nvidia-driver-580 package.)
|
|
|
|
|
#
|
|
|
|
|
# Coarse architecture heuristic by device-id range (validate against real
|
|
|
|
|
# hardware; refine the boundaries as needed):
|
|
|
|
|
# Fermi ( < 0x0f00) -> 390
|
|
|
|
|
# Kepler (0x0f00 .. 0x12ff) -> 470
|
|
|
|
|
# Maxwell+ ( >= 0x1300) -> 590 (current: Maxwell/Pascal/Turing/Ampere/Ada/...)
|
|
|
|
|
# Unknown/empty -> 590, the safest default for modern unknown hardware.
|
2026-06-04 21:30:38 +02:00
|
|
|
clawdie_live_gpu_nvidia_branch_for_device()
|
|
|
|
|
{
|
|
|
|
|
_device_id="$1"
|
2026-06-04 22:07:02 +02:00
|
|
|
[ -n "$_device_id" ] || { echo "590"; return 0; }
|
2026-06-04 21:30:38 +02:00
|
|
|
|
|
|
|
|
_device_num=$(printf '%d' "0x$_device_id" 2>/dev/null || echo "0")
|
|
|
|
|
|
2026-06-04 22:07:02 +02:00
|
|
|
if [ "$_device_num" -ge 4864 ]; then
|
|
|
|
|
echo "590" # >= 0x1300 Maxwell, Pascal, Turing, Ampere, Ada, ...
|
|
|
|
|
elif [ "$_device_num" -ge 3840 ]; then
|
|
|
|
|
echo "470" # 0x0f00 .. 0x12ff Kepler
|
|
|
|
|
else
|
|
|
|
|
echo "390" # < 0x0f00 Fermi
|
2026-06-04 21:30:38 +02:00
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
feat(gpu): universal NVIDIA lane — detect + install branch at boot (Sam & Claude)
Opt-in NVIDIA_UNIVERSAL lane (default NO; normal/single-branch builds unchanged):
one ISO that adapts to an unknown NVIDIA target.
- build.cfg: NVIDIA_UNIVERSAL flag.
- build.sh: install_nvidia_universal_repo() stages an on-image pkg repo with all
three branches (390/470/580 + settings), pkg-repo metadata, and a file:// repo
conf; universal mode bakes no branch and sets clawdie_live_gpu_mode=nvidia-auto.
- clawdie_live_gpu: nvidia-auto mode detects the device id (PR #30 fix) -> branch
{390,470,590} -> pkg-name -> `pkg install -r clawdie-nvidia` -> kldload, all
best-effort with fallback to integrated/scfb (never blocks boot).
- doc/NVIDIA-UNIVERSAL-HANDOFF.md: Codex FreeBSD build + hardware validation plan.
sh -n clean; detector+branch+pkg map unit-tested on Linux
(1c8c->590->nvidia-driver-580, 0fc8->470, 0e22->390). The pkg fetch/repo layout,
offline boot install, writable root, kernel ABI, and image size MUST be validated
on the FreeBSD build host + real NVIDIA hardware (see handoff).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 22:19:15 +02:00
|
|
|
# Map a branch label {390,470,590} to the on-image pkg name. The "590" lane is
|
|
|
|
|
# the current driver, which is the nvidia-driver-580 package.
|
|
|
|
|
clawdie_live_gpu_nvidia_pkg_for_branch()
|
|
|
|
|
{
|
|
|
|
|
case "$1" in
|
|
|
|
|
390) echo "nvidia-driver-390" ;;
|
|
|
|
|
470) echo "nvidia-driver-470" ;;
|
|
|
|
|
590) echo "nvidia-driver-580" ;;
|
|
|
|
|
*) return 1 ;;
|
|
|
|
|
esac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# nvidia-auto mode: detect the GPU, install the matching branch from the on-image
|
|
|
|
|
# clawdie-nvidia repo, and leave /boot/modules/nvidia.ko in place for select to
|
|
|
|
|
# load. Fully best-effort: any failure just logs and returns, so the caller falls
|
|
|
|
|
# back to the integrated/scfb path. Never blocks boot.
|
|
|
|
|
clawdie_live_gpu_install_nvidia()
|
|
|
|
|
{
|
|
|
|
|
_blocks="$1"
|
|
|
|
|
|
|
|
|
|
# Already installed (e.g. a previous boot) — nothing to do.
|
|
|
|
|
if [ -e /boot/modules/nvidia.ko ]; then
|
|
|
|
|
clawdie_live_gpu_log "nvidia.ko already present; skipping auto-install"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
_device_id=$(clawdie_live_gpu_nvidia_device_id "$_blocks" || true)
|
|
|
|
|
_branch=$(clawdie_live_gpu_nvidia_branch_for_device "$_device_id")
|
|
|
|
|
_pkg=$(clawdie_live_gpu_nvidia_pkg_for_branch "$_branch") || {
|
|
|
|
|
clawdie_live_gpu_log "WARN: no package mapping for branch ${_branch}; skipping NVIDIA auto-install"
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
clawdie_live_gpu_log "nvidia-auto: device ${_device_id:-unknown} -> branch ${_branch} (${_pkg})"
|
|
|
|
|
|
|
|
|
|
if ! command -v pkg >/dev/null 2>&1; then
|
|
|
|
|
clawdie_live_gpu_log "WARN: pkg not available; cannot auto-install NVIDIA"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Install only from the on-image repo so this works offline and never reaches
|
|
|
|
|
# the network during boot.
|
|
|
|
|
if env ASSUME_ALWAYS_YES=yes pkg install -y -r clawdie-nvidia "${_pkg}" nvidia-settings \
|
|
|
|
|
>> "$LOG_FILE" 2>&1; then
|
|
|
|
|
clawdie_live_gpu_log "nvidia-auto: installed ${_pkg}"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
clawdie_live_gpu_log "WARN: nvidia-auto install of ${_pkg} failed; falling back to integrated/scfb"
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-24 23:21:02 +02:00
|
|
|
clawdie_live_gpu_has_pci_vendor()
|
|
|
|
|
{
|
|
|
|
|
_blocks="$1"
|
|
|
|
|
_vendor_id="$2"
|
|
|
|
|
|
|
|
|
|
# Match the numeric PCI vendor on display-class blocks only. Do not use
|
|
|
|
|
# broad text matches like "Intel" here: unrelated vendor strings or
|
|
|
|
|
# subdevices can make an AMD system select i915kms and fail before SDDM.
|
|
|
|
|
echo "$_blocks" | awk -v vendor="$_vendor_id" '
|
|
|
|
|
BEGIN { RS = ""; IGNORECASE = 1; found = 0 }
|
|
|
|
|
$0 ~ ("(^|[[:space:]])vendor=" vendor "([[:space:]]|$)") { found = 1 }
|
|
|
|
|
END { exit(found ? 0 : 1) }
|
|
|
|
|
'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clawdie_live_gpu_select_modules()
|
|
|
|
|
{
|
|
|
|
|
_blocks="$1"
|
2026-06-04 21:30:38 +02:00
|
|
|
_mode="${clawdie_live_gpu_mode:-auto}"
|
|
|
|
|
_nvidia_branch="${clawdie_live_gpu_nvidia_branch:-}"
|
|
|
|
|
|
|
|
|
|
if [ "$_mode" = "safe" ]; then
|
|
|
|
|
clawdie_live_gpu_log "safe graphics mode requested; skipping KMS modules"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if clawdie_live_gpu_has_pci_vendor "$_blocks" "0x10de"; then
|
|
|
|
|
_device_id=$(clawdie_live_gpu_nvidia_device_id "$_blocks" || true)
|
|
|
|
|
_detected_branch=""
|
|
|
|
|
if [ -n "$_device_id" ]; then
|
|
|
|
|
_detected_branch=$(clawdie_live_gpu_nvidia_branch_for_device "$_device_id" || true)
|
|
|
|
|
clawdie_live_gpu_log "detected NVIDIA device id: ${_device_id} (recommended branch: ${_detected_branch:-unknown})"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ -e /boot/modules/nvidia.ko ]; then
|
|
|
|
|
if [ -n "$_nvidia_branch" ] && [ -n "$_detected_branch" ] && [ "$_nvidia_branch" != "$_detected_branch" ]; then
|
|
|
|
|
clawdie_live_gpu_log "WARN: staged NVIDIA branch ${_nvidia_branch} does not match detected device recommendation ${_detected_branch}; skipping proprietary load"
|
|
|
|
|
elif [ "$_mode" = "nvidia" ]; then
|
|
|
|
|
echo "nvidia-modeset nvidia"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
elif [ "$_mode" = "nvidia" ]; then
|
|
|
|
|
clawdie_live_gpu_log "WARN: NVIDIA mode requested but /boot/modules/nvidia.ko is missing"
|
|
|
|
|
fi
|
|
|
|
|
elif [ "$_mode" = "nvidia" ]; then
|
|
|
|
|
clawdie_live_gpu_log "WARN: NVIDIA mode requested but no NVIDIA display device was detected"
|
|
|
|
|
fi
|
2026-05-24 23:21:02 +02:00
|
|
|
|
|
|
|
|
# Hybrid laptops often expose Intel or AMD integrated graphics plus a
|
|
|
|
|
# discrete NVIDIA GPU. Prefer the integrated/open KMS path for live boot.
|
|
|
|
|
if clawdie_live_gpu_has_pci_vendor "$_blocks" "0x1002"; then
|
|
|
|
|
# amdgpu covers modern AMD; radeonkms is a best-effort fallback for
|
|
|
|
|
# older Radeon hardware only if amdgpu does not load.
|
|
|
|
|
echo "amdgpu radeonkms"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if clawdie_live_gpu_has_pci_vendor "$_blocks" "0x8086"; then
|
|
|
|
|
echo "i915kms"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if clawdie_live_gpu_has_pci_vendor "$_blocks" "0x15ad"; then
|
|
|
|
|
echo "vmwgfx"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if clawdie_live_gpu_has_pci_vendor "$_blocks" "0x10de"; then
|
|
|
|
|
# NVIDIA packages are bundled in the offline repo, but the live image
|
2026-06-04 21:30:38 +02:00
|
|
|
# only loads a concrete branch when one was explicitly staged.
|
2026-05-24 23:21:02 +02:00
|
|
|
if [ -e /boot/modules/nvidia.ko ]; then
|
|
|
|
|
echo "nvidia-modeset nvidia"
|
|
|
|
|
fi
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clawdie_live_gpu_load_module()
|
|
|
|
|
{
|
|
|
|
|
_module="$1"
|
|
|
|
|
|
|
|
|
|
if [ "$_module" = "radeonkms" ] && kldstat -n amdgpu.ko >/dev/null 2>&1; then
|
|
|
|
|
clawdie_live_gpu_log "skipping radeonkms because amdgpu is already loaded"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if kldstat -n "${_module}.ko" >/dev/null 2>&1; then
|
|
|
|
|
clawdie_live_gpu_log "module already loaded: ${_module}"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if kldload "$_module" >/dev/null 2>&1; then
|
|
|
|
|
clawdie_live_gpu_log "loaded module: ${_module}"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
clawdie_live_gpu_log "WARN: failed to load module: ${_module}"
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clawdie_live_gpu_start()
|
|
|
|
|
{
|
|
|
|
|
_blocks=$(clawdie_live_gpu_display_blocks)
|
|
|
|
|
if [ -z "$_blocks" ]; then
|
|
|
|
|
clawdie_live_gpu_log "no display-class PCI device detected; using scfb/vesa fallback"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
clawdie_live_gpu_log "detected display devices: $(echo "$_blocks" | grep -i '^vgapci' | tr '\n' ' ')"
|
feat(gpu): universal NVIDIA lane — detect + install branch at boot (Sam & Claude)
Opt-in NVIDIA_UNIVERSAL lane (default NO; normal/single-branch builds unchanged):
one ISO that adapts to an unknown NVIDIA target.
- build.cfg: NVIDIA_UNIVERSAL flag.
- build.sh: install_nvidia_universal_repo() stages an on-image pkg repo with all
three branches (390/470/580 + settings), pkg-repo metadata, and a file:// repo
conf; universal mode bakes no branch and sets clawdie_live_gpu_mode=nvidia-auto.
- clawdie_live_gpu: nvidia-auto mode detects the device id (PR #30 fix) -> branch
{390,470,590} -> pkg-name -> `pkg install -r clawdie-nvidia` -> kldload, all
best-effort with fallback to integrated/scfb (never blocks boot).
- doc/NVIDIA-UNIVERSAL-HANDOFF.md: Codex FreeBSD build + hardware validation plan.
sh -n clean; detector+branch+pkg map unit-tested on Linux
(1c8c->590->nvidia-driver-580, 0fc8->470, 0e22->390). The pkg fetch/repo layout,
offline boot install, writable root, kernel ABI, and image size MUST be validated
on the FreeBSD build host + real NVIDIA hardware (see handoff).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 22:19:15 +02:00
|
|
|
|
|
|
|
|
# Universal lane: install the matching NVIDIA branch before module selection.
|
|
|
|
|
# Best-effort — on failure select_modules just falls through to integrated.
|
|
|
|
|
if [ "${clawdie_live_gpu_mode:-auto}" = "nvidia-auto" ] &&
|
|
|
|
|
clawdie_live_gpu_has_pci_vendor "$_blocks" "0x10de"; then
|
|
|
|
|
clawdie_live_gpu_install_nvidia "$_blocks" || true
|
|
|
|
|
fi
|
|
|
|
|
|
2026-05-24 23:21:02 +02:00
|
|
|
_modules=$(clawdie_live_gpu_select_modules "$_blocks")
|
|
|
|
|
if [ -z "$_modules" ]; then
|
|
|
|
|
clawdie_live_gpu_log "no live KMS module selected; using scfb/vesa fallback"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
clawdie_live_gpu_log "selected live KMS modules: ${_modules}"
|
|
|
|
|
for _module in $_modules; do
|
|
|
|
|
clawdie_live_gpu_load_module "$_module" || true
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
load_rc_config "$name"
|
|
|
|
|
: ${clawdie_live_gpu_enable:="NO"}
|
2026-06-04 21:30:38 +02:00
|
|
|
: ${clawdie_live_gpu_mode:="auto"}
|
|
|
|
|
: ${clawdie_live_gpu_nvidia_branch:=""}
|
2026-05-24 23:21:02 +02:00
|
|
|
|
|
|
|
|
run_rc_command "$1"
|