diff --git a/build.cfg b/build.cfg index c092f30..814f4e5 100644 --- a/build.cfg +++ b/build.cfg @@ -43,6 +43,14 @@ DEFAULT_DESKTOP="xfce" # operator USB desktop # intel | amd | nvidia-590 | nvidia-470 | nvidia-390 | vesa | "" (auto-detect) GPU_DRIVER="" +# Universal NVIDIA lane (opt-in). When YES, the image carries an on-image NVIDIA +# pkg repo for all three branches (390/470/580), does NOT bake a single branch, +# and clawdie_live_gpu runs in "nvidia-auto": at boot it detects the GPU, installs +# the matching branch from the on-image repo, and kldloads it before SDDM. On any +# failure it falls back to the integrated/scfb path (never worse than today). +# Builds a larger image. Leave NO for single-branch GPU_DRIVER=nvidia-* builds. +NVIDIA_UNIVERSAL="${NVIDIA_UNIVERSAL:-NO}" + # Deploy target TARGET="baremetal" # vps | baremetal diff --git a/build.sh b/build.sh index 2782dd5..827608a 100755 --- a/build.sh +++ b/build.sh @@ -119,6 +119,7 @@ echo " Clawdie : ${CLAWDIE_REF}" echo " Desktop : ${DEFAULT_DESKTOP}" echo " Pkg : ${DEFAULT_PKG_BRANCH}" echo " GPU : ${GPU_DRIVER:-auto-detect}" +echo " NVIDIA universal : ${NVIDIA_UNIVERSAL:-NO}" echo " Target : ${TARGET:-baremetal}" echo " Colibri : ${FEATURE_COLIBRI:-NO}" echo " Clawdie agent : ${FEATURE_CLAWDIE:-NO}" @@ -906,6 +907,48 @@ install_clawdie_service() { fi } +# Stage an on-image NVIDIA pkg repo (all branches) so clawdie_live_gpu can +# `pkg install` the detected branch at boot (NVIDIA_UNIVERSAL lane). +# +# FreeBSD-build-host step (authored on Linux; runs + must be validated on +# FreeBSD). Verify on the build host: (1) the `pkg fetch -o` layout matches what +# `pkg repo` expects, (2) the dependency closure is complete for offline boot +# install, (3) image size headroom, (4) `pkg install -r clawdie-nvidia` resolves +# from file:// at boot. See doc handoff. +install_nvidia_universal_repo() { + [ "${NVIDIA_UNIVERSAL:-NO}" = "YES" ] || { + echo " NVIDIA universal repo staging disabled (NVIDIA_UNIVERSAL=${NVIDIA_UNIVERSAL:-NO})" + return 0 + } + + echo " Staging universal NVIDIA repo (all branches) into image..." + _nv_repo="${MOUNT_POINT}/usr/local/share/clawdie/nvidia-repo" + mkdir -p "${_nv_repo}" + + # Fetch all three branches + deps into the on-image repo dir, then build repo + # metadata. Uses pkg's own dependency resolution so the closure is complete. + if ! env ASSUME_ALWAYS_YES=yes pkg fetch -y -o "${_nv_repo}" -d \ + nvidia-driver-390 nvidia-driver-470 nvidia-driver-580 nvidia-settings nvidia-xconfig; then + echo "ERROR: failed to fetch NVIDIA packages for universal repo" + exit 1 + fi + if ! pkg repo "${_nv_repo}"; then + echo "ERROR: failed to generate NVIDIA universal repo metadata" + exit 1 + fi + + mkdir -p "${MOUNT_POINT}/usr/local/etc/pkg/repos" + cat > "${MOUNT_POINT}/usr/local/etc/pkg/repos/clawdie-nvidia.conf" <<'EOF' +# On-image NVIDIA package repo for the universal GPU lane. Consumed at boot by +# clawdie_live_gpu (nvidia-auto mode) via: pkg install -r clawdie-nvidia ... +clawdie-nvidia: { + url: "file:///usr/local/share/clawdie/nvidia-repo", + enabled: yes +} +EOF + echo " NVIDIA universal repo staged at /usr/local/share/clawdie/nvidia-repo" +} + install_live_npm_globals() { echo " Installing bundled npm globals into live image..." @@ -1561,6 +1604,15 @@ EOF ;; esac + # Universal NVIDIA lane: no branch is baked; clawdie_live_gpu installs the + # matching one from the on-image repo at boot. Overrides the mode set above. + # kld_list intentionally does NOT preload nvidia (it is not installed yet at + # first boot); the rc.d service kldloads it after install. + if [ "${NVIDIA_UNIVERSAL:-NO}" = "YES" ]; then + set_config_line "${MOUNT_POINT}/etc/rc.conf" 'clawdie_live_gpu_mode="nvidia-auto"' + set_config_line "${MOUNT_POINT}/etc/rc.conf" 'clawdie_live_gpu_nvidia_branch=""' + fi + mkdir -p "${MOUNT_POINT}/etc/ssh/sshd_config.d" install -m 0644 "${LIVE_SESSION_DIR}/sshd-live.conf" \ "${MOUNT_POINT}/etc/ssh/sshd_config.d/clawdie-live.conf" @@ -2158,6 +2210,7 @@ install_live_runtime_packages configure_live_operator_session install_colibri_service install_clawdie_service +install_nvidia_universal_repo # Copy payload # Rebuild payload paths from scratch inside the reusable work image. A failed diff --git a/doc/NVIDIA-UNIVERSAL-HANDOFF.md b/doc/NVIDIA-UNIVERSAL-HANDOFF.md new file mode 100644 index 0000000..016f493 --- /dev/null +++ b/doc/NVIDIA-UNIVERSAL-HANDOFF.md @@ -0,0 +1,74 @@ +# NVIDIA universal lane — Codex build + hardware validation handoff + +**From:** Claude (Linux) · **To:** Codex ISO Builder (FreeBSD 15 host) +**Goal:** one ISO that boots on any NVIDIA machine — detect the GPU pre-SDDM, +install the matching branch from an on-image repo, kldload it, then SDDM/XFCE. + +Authored on Linux (sh -n clean; detector + branch/pkg map unit-tested). The +package/boot behavior **must be built and proven on FreeBSD + real NVIDIA +hardware** — it cannot be validated from Linux. + +## What landed (behind `NVIDIA_UNIVERSAL`, default NO — normal builds unaffected) + +- `build.cfg`: `NVIDIA_UNIVERSAL` flag. +- `build.sh`: + - `install_nvidia_universal_repo()` — `pkg fetch -d` the three families + (`nvidia-driver-390/470/580` + settings) into + `/usr/local/share/clawdie/nvidia-repo`, `pkg repo` it, write + `/usr/local/etc/pkg/repos/clawdie-nvidia.conf` (file:// , enabled). + - In universal mode: no branch baked into the root; rc.conf + `clawdie_live_gpu_mode="nvidia-auto"`. +- `live/operator-session/clawdie-live-gpu` (`nvidia-auto` mode): detect device id + → branch {390,470,590} → `pkg install -r clawdie-nvidia nvidia-driver- +nvidia-settings` → kldload via existing select/load. **Best-effort:** any + failure falls through to the integrated/scfb path — never worse than today. + +## Must verify on the FreeBSD build host + +1. **`pkg fetch -o` / `pkg repo` layout** — confirm `pkg fetch -y -o DIR -d ...` + places archives where `pkg repo DIR` expects them; adjust if `pkg repo` needs + `DIR/All`. Confirm the dependency closure is complete (offline boot install + must not reach the network). +2. **Boot install command** — `pkg install -y -r clawdie-nvidia nvidia-driver-470 +nvidia-settings` resolves purely from the file:// repo with no network. +3. **Writable root at boot** — the USB-root install must allow `pkg install` + before SDDM (it does on a real on-USB FreeBSD; confirm). +4. **Kernel ABI** — the staged kmod packages must match the image's kernel. +5. **Image size** — three branches + deps add several hundred MB; confirm + headroom against `IMAGE_SIZE`. +6. **Exactly one branch** installed at boot (no mixing). + +## Build commands + +```sh +# colibri artifacts first (do NOT cargo clean after) +cd /home/clawdie/colibri && git fetch origin && git reset --hard origin/main +cargo build --workspace --release + +# universal image (set COLIBRI_REPO explicitly if building from a tmp worktree) +cd /home/clawdie/clawdie-iso && git fetch origin && git reset --hard origin/main +sudo env NVIDIA_UNIVERSAL=YES FEATURE_CLAWDIE=YES \ + COLIBRI_REPO=/home/clawdie/colibri \ + CLAWDIE_ARTIFACT_DIR=/home/clawdie/colibri/target/release \ + ./build.sh --skip-memstick-fetch --live-default-password +``` + +## Hardware acceptance + +1. Boot on the NVIDIA target. +2. `cat /var/log/clawdie-live-gpu.log` — expect: detected device id, chosen + branch + pkg, "installed nvidia-driver-", selected/loaded modules. +3. `kldstat | grep nvidia` and SDDM → XFCE comes up accelerated. +4. If install/load failed, the log shows the fallback and the desktop still + comes up on integrated/scfb (no hard failure). + +## Deletion criteria + +Delete this handoff once a `NVIDIA_UNIVERSAL=YES` image has, on real NVIDIA +hardware, auto-installed the correct branch and reached XFCE — with the result +recorded below. + +## Results + +_(Codex: build host, GPU model + device id, branch chosen, pkg install outcome, +image size delta, SDDM/XFCE result.)_ diff --git a/live/operator-session/clawdie-live-gpu b/live/operator-session/clawdie-live-gpu index 8fadde7..65f4a68 100644 --- a/live/operator-session/clawdie-live-gpu +++ b/live/operator-session/clawdie-live-gpu @@ -79,6 +79,57 @@ clawdie_live_gpu_nvidia_branch_for_device() fi } +# 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 +} + clawdie_live_gpu_has_pci_vendor() { _blocks="$1" @@ -190,6 +241,14 @@ clawdie_live_gpu_start() fi clawdie_live_gpu_log "detected display devices: $(echo "$_blocks" | grep -i '^vgapci' | tr '\n' ' ')" + + # 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 + _modules=$(clawdie_live_gpu_select_modules "$_blocks") if [ -z "$_modules" ]; then clawdie_live_gpu_log "no live KMS module selected; using scfb/vesa fallback"