diff options
| author | Open-IOV <dev@open-iov.org> | 2026-09-23 05:44:08 -0400 |
|---|---|---|
| committer | Open-IOV <dev@open-iov.org> | 2026-09-23 05:46:43 -0400 |
| commit | 68cdd7728a7cc6715bbbff7decfe2b11c3bdf558 (patch) | |
| tree | 3dc8ce2e6af313a97ec6852f5c663a9a93665d2e /scripts | |
| download | open-iov-68cdd7728a7cc6715bbbff7decfe2b11c3bdf558.tar.gz open-iov-68cdd7728a7cc6715bbbff7decfe2b11c3bdf558.zip | |
Open-IOV: initial public release
Open-IOV virtualizes NVIDIA GPUs so that unmodified guest drivers run with
real GPU functionality - CUDA first, 3D and video to follow - on unmodified
hosts, without a proprietary vGPU license and without patching any driver,
firmware or hypervisor.
Core principle: emulate the interface, pass through the work.
kernel/ open-iov-vfio.ko - host VFIO mdev driver: virtual GPU device
(PCI config space, BAR shadows, MSI-X), GSP boot emulation,
GSP-RM message-queue/RPC emulation, memory model (GPU-VA to
guest-PA discovery) and the semaphore-completion service that
advances guest UVM progress.
userspace/ libiov.so management API and examples.
tools/ guest diagnostics, firmware analysis wrappers, RM probes.
scripts/ stack manager, VM harness, build/load/test automation.
config/ hardware/version profiles (the portability surface).
docs/ documentation tree - start at docs/README.md.
wiki/ long-form firmware and protocol deep dives.
Status: initialization works end to end for a stock 570.144 Linux guest on
Turing (TU104): driver probe, nvidia-smi, the full GSP-RM control battery,
object creation and the early CUDA/UVM start-up path. GPU work forwarding -
the step that makes CUDA kernels execute on real hardware - is the active
work item; see docs/04-implementation/01-known-knowns-and-unknowns.md.
License: BSD-3-Clause for the project; GPL-2.0 for kernel modules that link
GPL-only kernel interfaces. See LICENSE and docs/09-reference/legal-and-licensing.md.
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/auto-opencode-setup.sh | 327 | ||||
| -rwxr-xr-x | scripts/build_nvidia_openrm.sh | 61 | ||||
| -rwxr-xr-x | scripts/create_mdev.sh | 86 | ||||
| -rwxr-xr-x | scripts/debug_guest_init.sh | 172 | ||||
| -rwxr-xr-x | scripts/launch_qemu_vgpu.sh | 198 | ||||
| -rwxr-xr-x | scripts/load_vgpu_stack.sh | 57 | ||||
| -rw-r--r-- | scripts/qemu_gdb_attach.sh | 58 | ||||
| -rwxr-xr-x | scripts/setup_guest_driver.sh | 99 | ||||
| -rwxr-xr-x | scripts/stack_manager.sh | 437 | ||||
| -rwxr-xr-x | scripts/test_cuda_workloads.sh | 45 | ||||
| -rwxr-xr-x | scripts/test_graphics_workloads.sh | 33 | ||||
| -rwxr-xr-x | scripts/test_gsp_emu.sh | 59 | ||||
| -rwxr-xr-x | scripts/test_guest_driver.sh | 75 | ||||
| -rwxr-xr-x | scripts/test_vgpu_stack.sh | 149 | ||||
| -rwxr-xr-x | scripts/test_windows_guest.sh | 36 | ||||
| -rwxr-xr-x | scripts/unload_vgpu_stack.sh | 36 | ||||
| -rwxr-xr-x | scripts/windows_guest_automation.sh | 220 |
17 files changed, 2148 insertions, 0 deletions
diff --git a/scripts/auto-opencode-setup.sh b/scripts/auto-opencode-setup.sh new file mode 100755 index 0000000..4126d3d --- /dev/null +++ b/scripts/auto-opencode-setup.sh @@ -0,0 +1,327 @@ +#!/bin/bash +# auto-opencode-setup.sh - Configure auto-opencode session on login +# Usage: sudo ./auto-opencode-setup.sh [enable|disable] [graphical|multi-user] [auto-login] + +set -euo pipefail + +AUTO_OPENCODE_DIR="$HOME/.config/auto-opencode" +AUTO_OPENCODE_SCRIPT="$AUTO_OPENCODE_DIR/auto-opencode.sh" +AUTO_OPENCODE_MARKER="$AUTO_OPENCODE_DIR/enabled" +AUTO_LOGIN_MARKER="$AUTO_OPENCODE_DIR/auto-login" +TARGET_MARKER="$AUTO_OPENCODE_DIR/target" + +log_info() { echo -e "\033[0;34m[INFO]\033[0m $1"; } +log_ok() { echo -e "\033[0;32m[OK]\033[0m $1"; } +log_warn() { echo -e "\033[1;33m[WARN]\033[0m $1"; } +log_error() { echo -e "\033[0;31m[ERROR]\033[0m $1"; } + +usage() { + cat <<EOF +Usage: $0 [enable|disable] [graphical|multi-user] [auto-login] [auto-opencode] + +Configure auto-opencode session on login. + +Commands: + enable - Enable auto-opencode + disable - Disable auto-opencode + status - Show current configuration + +Options: + graphical|multi-user - Boot target (default: graphical) + auto-login - Enable automatic login (graphical: GDM, multi-user: getty) + auto-opencode - Start opencode tmux session on login + +Examples: + $0 enable graphical auto-login auto-opencode + $0 enable multi-user auto-opencode + $0 disable + $0 status +EOF +} + +create_auto_opencode_script() { + mkdir -p "$AUTO_OPENCODE_DIR" + + cat > "$AUTO_OPENCODE_SCRIPT" <<'SCRIPTEOF' +#!/bin/bash +# auto-opencode.sh - Runs on login to start opencode tmux session +# This script is sourced from .zprofile (multi-user) or .xprofile (graphical) + +AUTO_OPENCODE_DIR="$HOME/.config/auto-opencode" +AUTO_OPENCODE_MARKER="$AUTO_OPENCODE_DIR/enabled" +AUTO_LOGIN_MARKER="$AUTO_OPENCODE_DIR/auto-login" + +# Check if auto-opencode is enabled +[[ -f "$AUTO_OPENCODE_MARKER" ]] || exit 0 + +# Prevent multiple runs +if [[ -n "$AUTO_OPENCODE_STARTED" ]]; then + exit 0 +fi +export AUTO_OPENCODE_STARTED=1 + +# Only run in interactive shells +[[ $- == *i* ]] || exit 0 + +# Check if tmux is available +command -v tmux &>/dev/null || exit 0 +command -v opencode &>/dev/null || exit 0 + +# Check if we're already in tmux +[[ -n "$TMUX" ]] && exit 0 + +# Target directory +TARGET_DIR="__OPEN_IOV_PARENT__" + +# Session name +SESSION_NAME="auto-opencode" + +# Check if session already exists +if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then + echo "Attaching to existing $SESSION_NAME session..." + exec tmux attach-session -t "$SESSION_NAME" +fi + +# Create new tmux session with opencode +echo "Starting auto-opencode session..." +cd "$TARGET_DIR" + +# Start tmux session +tmux new-session -d -s "$SESSION_NAME" -c "$TARGET_DIR" \ + "opencode --dangerously-skip-permissions" + +# Wait a moment for opencode to start +sleep 2 + +# Send initial commands to read AGENTS.md and handoff +tmux send-keys -t "$SESSION_NAME" "cat AGENTS.md" Enter +sleep 1 +tmux send-keys -t "$SESSION_NAME" "cat Handoff-vGPU-IO.md" Enter +sleep 1 + +# Attach to session +exec tmux attach-session -t "$SESSION_NAME" +SCRIPTEOF + + # Bake in the repo parent dir (resolved at setup time) + local repo_parent + repo_parent="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" + sed -i "s|__OPEN_IOV_PARENT__|$repo_parent|g" "$AUTO_OPENCODE_SCRIPT" + chmod +x "$AUTO_OPENCODE_SCRIPT" + log_ok "Created auto-opencode script: $AUTO_OPENCODE_SCRIPT" +} + +setup_graphical_autologin() { + log_info "Setting up graphical auto-login (GDM)..." + + # Create GDM custom.conf for auto-login + sudo mkdir -p /etc/gdm3 + sudo tee /etc/gdm3/custom.conf > /dev/null <<EOF +[daemon] +AutomaticLoginEnable=true +AutomaticLogin=${USER} +WaylandEnable=false + +[security] + +[xdmcp] + +[chooser] + +[debug] +EOF + + # Add auto-opencode to graphical session startup + mkdir -p $HOME/.config/autostart + cat > $HOME/.config/autostart/auto-opencode.desktop <<EOF +[Desktop Entry] +Type=Application +Name=Auto OpenCode +Exec=$HOME/.config/auto-opencode/auto-opencode.sh +Hidden=false +NoDisplay=false +X-GNOME-Autostart-enabled=true +EOF + + log_ok "Graphical auto-login configured" +} + +setup_multiuser_autologin() { + log_info "Setting up multi-user auto-login (getty)..." + + # Create systemd override for getty@tty1 + sudo mkdir -p /etc/systemd/system/getty@tty1.service.d + sudo tee /etc/systemd/system/getty@tty1.service.d/autologin.conf > /dev/null <<EOF +[Service] +ExecStart= +ExecStart=-/sbin/agetty --autologin rmcore --noclear %I \$TERM +EOF + + # Add auto-opencode to .zprofile for multi-user login + if ! grep -q "auto-opencode.sh" $HOME/.zprofile 2>/dev/null; then + cat >> $HOME/.zprofile <<'EOF' + +# Auto-opencode on login +if [[ -f $HOME/.config/auto-opencode/auto-opencode.sh ]]; then + source $HOME/.config/auto-opencode/auto-opencode.sh +fi +EOF + fi + + log_ok "Multi-user auto-login configured" +} + +disable_autologin() { + log_info "Disabling auto-login..." + + # Remove GDM auto-login + if [[ -f /etc/gdm3/custom.conf ]]; then + sudo sed -i '/^AutomaticLoginEnable=/d' /etc/gdm3/custom.conf + sudo sed -i '/^AutomaticLogin=/d' /etc/gdm3/custom.conf + fi + + # Remove getty auto-login + sudo rm -f /etc/systemd/system/getty@tty1.service.d/autologin.conf + + # Remove autostart desktop entry + rm -f $HOME/.config/autostart/auto-opencode.desktop + + # Remove from .zprofile + sed -i '/auto-opencode.sh/d' $HOME/.zprofile 2>/dev/null || true + + log_ok "Auto-login disabled" +} + +enable_auto_opencode() { + local target="${1:-graphical}" + local auto_login="${2:-false}" + local auto_opencode="${3:-false}" + + log_info "Enabling auto-opencode (target: $target, auto-login: $auto_login, auto-opencode: $auto_opencode)" + + create_auto_opencode_script + + # Set target + echo "$target" > "$TARGET_MARKER" + + # Set boot target + sudo systemctl set-default "$target.target" + log_ok "Boot target set to $target.target" + + # Handle auto-login + if [[ "$auto_login" == "true" ]]; then + touch "$AUTO_LOGIN_MARKER" + if [[ "$target" == "graphical" ]]; then + setup_graphical_autologin + else + setup_multiuser_autologin + fi + else + rm -f "$AUTO_LOGIN_MARKER" + disable_autologin + fi + + # Handle auto-opencode + if [[ "$auto_opencode" == "true" ]]; then + touch "$AUTO_OPENCODE_MARKER" + log_ok "Auto-opencode enabled" + else + rm -f "$AUTO_OPENCODE_MARKER" + log_ok "Auto-opencode disabled" + fi + + log_ok "Configuration complete" +} + +disable_auto_opencode() { + log_info "Disabling auto-opencode..." + + rm -f "$AUTO_OPENCODE_MARKER" + rm -f "$AUTO_LOGIN_MARKER" + rm -f "$TARGET_MARKER" + + disable_autologin + + # Remove auto-opencode script + rm -f "$AUTO_OPENCODE_SCRIPT" + + log_ok "Auto-opencode disabled" +} + +show_status() { + echo "═══════════════════════════════════════════════════════════════" + echo " AUTO-OPENCODE STATUS" + echo "═══════════════════════════════════════════════════════════════" + + if [[ -f "$AUTO_OPENCODE_MARKER" ]]; then + echo " Auto-opencode: ENABLED" + else + echo " Auto-opencode: DISABLED" + fi + + if [[ -f "$AUTO_LOGIN_MARKER" ]]; then + echo " Auto-login: ENABLED" + else + echo " Auto-login: DISABLED" + fi + + if [[ -f "$TARGET_MARKER" ]]; then + echo " Boot target: $(cat "$TARGET_MARKER")" + else + echo " Boot target: $(systemctl get-default | sed 's/.target$//')" + fi + + echo " Current default: $(systemctl get-default)" + echo "═══════════════════════════════════════════════════════════════" +} + +main() { + local action="${1:-status}" + shift || true + + local target="graphical" + local auto_login="false" + local auto_opencode="false" + + # Parse remaining arguments + for arg in "$@"; do + case "$arg" in + graphical|multi-user) + target="$arg" + ;; + auto-login|auto-login=on) + auto_login="true" + ;; + auto-login=off) + auto_login="false" + ;; + auto-opencode|auto-opencode=on) + auto_opencode="true" + ;; + auto-opencode=off) + auto_opencode="false" + ;; + *) + log_warn "Unknown argument: $arg" + ;; + esac + done + + case "$action" in + enable) + enable_auto_opencode "$target" "$auto_login" "$auto_opencode" + ;; + disable) + disable_auto_opencode + ;; + status) + show_status + ;; + *) + usage + exit 1 + ;; + esac +} + +main "$@"
\ No newline at end of file diff --git a/scripts/build_nvidia_openrm.sh b/scripts/build_nvidia_openrm.sh new file mode 100755 index 0000000..89e058b --- /dev/null +++ b/scripts/build_nvidia_openrm.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# Build NVIDIA OpenRM kernel modules with Open-IOV vGPU VFIO symbols +# This script ensures KBUILD_EXTRA_SYMBOLS is correctly passed to the build + +set -e + +OPEN_IOV_ROOT="${OPEN_IOV_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +NVIDIA_OPENRM_DIR="$OPEN_IOV_ROOT/nvidia-open-gpu-kernel-modules" +KERNEL_DIR="$OPEN_IOV_ROOT/kernel" +SYMVERS_FILE="$KERNEL_DIR/Module.symvers" + +echo "=== Building NVIDIA OpenRM with Open-IOV vGPU VFIO symbols ===" +echo "Open-IOV root: $OPEN_IOV_ROOT" +echo "NVIDIA OpenRM dir: $NVIDIA_OPENRM_DIR" +echo "Kernel Module.symvers: $SYMVERS_FILE" + +# Check if open-iov-vfio.ko has been built (provides Module.symvers) +if [ ! -f "$SYMVERS_FILE" ]; then + echo "ERROR: $SYMVERS_FILE not found!" + echo "Please build open-iov-vfio.ko first: cd $OPEN_IOV_ROOT && make kernel" + exit 1 +fi + +echo "Found Module.symvers with $(wc -l < "$SYMVERS_FILE") exported symbols" +echo "Key vGPU symbols:" +grep -i vgpu "$SYMVERS_FILE" | head -5 + +# Build NVIDIA OpenRM kernel modules +cd "$NVIDIA_OPENRM_DIR/kernel-open" + +# Clean previous build to ensure fresh symbol resolution +echo "Cleaning previous build..." +make clean + +echo "Building NVIDIA OpenRM modules with KBUILD_EXTRA_SYMBOLS..." +KBUILD_EXTRA_SYMBOLS="$SYMVERS_FILE" make -j$(nproc) modules + +# Verify the symbols are resolved +echo "" +echo "=== Verification ===" +echo "Checking nvidia.ko for vGPU VFIO symbols..." +if modinfo nvidia.ko 2>/dev/null | grep -q "nvidia_vgpu_vfio"; then + echo "✓ nvidia.ko has vGPU VFIO symbols" +else + echo "⚠ nvidia.ko may not have vGPU VFIO symbols (check modpost output above)" +fi + +echo "" +echo "Checking Module.symvers for vGPU symbols..." +grep -i vgpu Module.symvers | head -5 + +echo "" +echo "=== Build Complete ===" +echo "nvidia.ko location: $NVIDIA_OPENRM_DIR/kernel-open/nvidia.ko" +echo "" +echo "To load the stack:" +echo " sudo insmod $NVIDIA_OPENRM_DIR/kernel-open/nvidia.ko" +echo " sudo insmod $KERNEL_DIR/open-iov-vfio.ko" +echo " sudo cp $OPEN_IOV_ROOT/firmware/57X-GSP/570.144/gsp-570.144.fwimage.bin /lib/firmware/" +echo " ./scripts/create_mdev.sh" +echo " ./scripts/launch_qemu_vgpu.sh"
\ No newline at end of file diff --git a/scripts/create_mdev.sh b/scripts/create_mdev.sh new file mode 100755 index 0000000..a6ea91e --- /dev/null +++ b/scripts/create_mdev.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# create_mdev.sh - Create NVIDIA vGPU mediated device for QEMU +# Usage: ./create_mdev.sh [PCI_ADDRESS] [VGPU_TYPE] + +set -euo pipefail + +PCI_ADDR="${1:-}" +VGPU_TYPE="${2:-pci-nvidia-vgpu-turing}" + +# Supported vGPU types (matching the mdev type names) +VALID_TYPES=("pci-nvidia-vgpu-ampere" "pci-nvidia-vgpu-hopper" "pci-nvidia-vgpu-turing" "pci-nvidia-vgpu-pascal") + +# Find NVIDIA GPU if not specified +if [[ -z "$PCI_ADDR" ]]; then + echo "Scanning for NVIDIA GPUs..." + mapfile -t GPUS < <(lspci -D -d 10de: | grep -E "VGA|3D controller" | awk '{print $1}') + if [[ ${#GPUS[@]} -eq 0 ]]; then + echo "ERROR: No NVIDIA GPU found" + exit 1 + elif [[ ${#GPUS[@]} -eq 1 ]]; then + PCI_ADDR="${GPUS[0]}" + echo "Auto-selected GPU: $PCI_ADDR" + else + echo "Multiple GPUs found:" + for i in "${!GPUS[@]}"; do + echo " [$i] ${GPUS[$i]}" + done + read -p "Select GPU [0-$((${#GPUS[@]}-1))]: " idx + PCI_ADDR="${GPUS[$idx]}" + fi +fi + +# Validate PCI address format +if [[ ! "$PCI_ADDR" =~ ^[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.[0-9a-fA-F]$ ]]; then + echo "ERROR: Invalid PCI address format. Expected: dddd:bb:dd.f" + exit 1 +fi + +# Check if GPU exists +if [[ ! -e "/sys/bus/pci/devices/$PCI_ADDR" ]]; then + echo "ERROR: PCI device $PCI_ADDR not found" + exit 1 +fi + +# Validate vGPU type +if [[ ! " ${VALID_TYPES[*]} " =~ " ${VGPU_TYPE} " ]]; then + echo "ERROR: Invalid vGPU type. Valid types: ${VALID_TYPES[*]}" + exit 1 +fi + +MDEV_TYPE_PATH="/sys/bus/pci/devices/$PCI_ADDR/mdev_supported_types/$VGPU_TYPE" + +if [[ ! -d "$MDEV_TYPE_PATH" ]]; then + echo "ERROR: vGPU type $VGPU_TYPE not supported on $PCI_ADDR" + echo "Available types:" + ls "/sys/bus/pci/devices/$PCI_ADDR/mdev_supported_types/" 2>/dev/null || echo " (none - check driver loaded)" + exit 1 +fi + +# Check available instances +AVAILABLE=$(cat "$MDEV_TYPE_PATH/available_instances" 2>/dev/null || echo "0") +if [[ "$AVAILABLE" -le 0 ]]; then + echo "ERROR: No available instances for $VGPU_TYPE on $PCI_ADDR" + exit 1 +fi + +echo "Creating $VGPU_TYPE on $PCI_ADDR..." + +# Generate UUID +UUID=$(uuidgen) +echo "$UUID" | sudo tee "$MDEV_TYPE_PATH/create" > /dev/null + +# Verify creation +MDEV_PATH="/sys/bus/mdev/devices/$UUID" +if [[ -d "$MDEV_PATH" ]]; then + echo "SUCCESS: Created mdev device $UUID" + echo " Path: $MDEV_PATH" + echo " PCI: $PCI_ADDR" + echo " Type: $VGPU_TYPE" + echo "" + echo "For QEMU, use:" + echo " -device vfio-pci,sysfsdev=$MDEV_PATH,display=off" +else + echo "ERROR: Failed to create mdev device" + exit 1 +fi
\ No newline at end of file diff --git a/scripts/debug_guest_init.sh b/scripts/debug_guest_init.sh new file mode 100755 index 0000000..324f403 --- /dev/null +++ b/scripts/debug_guest_init.sh @@ -0,0 +1,172 @@ +#!/bin/bash +# debug_guest_init.sh - One-command debug launch for guest NVIDIA driver initialization +# Usage: ./debug_guest_init.sh [options] + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BASE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Defaults +GDB_PORT=1234 +FREEZE_AT_START=true +MONITOR_GUEST=true +GUEST_SERIAL="/dev/ttyS0" +DURATION=300 +OUTPUT_DIR="/tmp/gsp_emu_debug_$(date +%Y%m%d_%H%M%S)" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +log_error() { echo -e "${RED}[ERROR]${NC} $1"; } +log_ok() { echo -e "${GREEN}[OK]${NC} $1"; } + +usage() { + cat <<EOF +Usage: $0 [options] + +Debug guest NVIDIA driver initialization with full observability. + +Options: + --gdb-port PORT GDB server port (default: 1234) + --no-freeze Don't freeze QEMU at startup (-S flag) + --no-monitor Disable guest init monitor + --guest-serial DEV Guest serial device (default: /dev/ttyS0) + --duration SEC Monitor duration in seconds (default: 300) + --output-dir DIR Output directory (default: /tmp/gsp_emu_debug_TIMESTAMP) + --vmlinux PATH Path to guest vmlinux with debug symbols + --help Show this help + +This script: + 1. Enables kernel tracepoints for GSP emulation + 2. Launches QEMU with GDB server + 3. Starts guest init monitor (correlates host traces + guest serial) + 4. Opens GDB with nvidia_init.gdb script + 5. Saves all logs to output directory + +Example: + $0 --vmlinux /path/to/guest/vmlinux + $0 --no-freeze --duration 600 +EOF +} + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --gdb-port) GDB_PORT="$2"; shift 2 ;; + --no-freeze) FREEZE_AT_START=false; shift ;; + --no-monitor) MONITOR_GUEST=false; shift ;; + --guest-serial) GUEST_SERIAL="$2"; shift 2 ;; + --duration) DURATION="$2"; shift 2 ;; + --output-dir) OUTPUT_DIR="$2"; shift 2 ;; + --vmlinux) VMLINUX="$2"; shift 2 ;; + --help) usage; exit 0 ;; + *) log_error "Unknown option: $1"; usage; exit 1 ;; + esac +done + +mkdir -p "$OUTPUT_DIR" +log_info "Output directory: $OUTPUT_DIR" + +# Check prerequisites +log_info "Checking prerequisites..." + +# Check for mdev +MDEV_UUID=$(ls /sys/bus/mdev/devices/ 2>/dev/null | head -1) +if [[ -z "$MDEV_UUID" ]]; then + log_error "No mdev device found. Run create_mdev.sh first." + exit 1 +fi +log_info "Using mdev: $MDEV_UUID" + +# Build QEMU command +QEMU_CMD=( + qemu-system-x86_64 + -enable-kvm + -cpu host + -smp 4 + -m 8G + -device vfio-pci,sysfsdev=/sys/bus/mdev/devices/$MDEV_UUID,display=off + -drive file=/var/lib/libvirt/images/ubuntu-vgpu.qcow2,format=qcow2,if=virtio + -netdev user,id=net0,hostfwd=tcp::2222-:22 + -device virtio-net-pci,netdev=net0 + -nographic + -serial mon:stdio +) + +if [[ "$FREEZE_AT_START" == "true" ]]; then + QEMU_CMD+=(-s -S) +else + QEMU_CMD+=(-s) +fi + +if [[ "$GDB_PORT" != "1234" ]]; then + QEMU_CMD+=(-gdb "tcp::$GDB_PORT") +fi + +# Start guest init monitor in background +MONITOR_PID="" +if [[ "$MONITOR_GUEST" == "true" ]]; then + log_info "Starting guest init monitor..." + python3 "$BASE_DIR/tools/guest_init_monitor.py" \ + --guest-serial "$GUEST_SERIAL" \ + --duration "$DURATION" \ + > "$OUTPUT_DIR/guest_monitor.log" 2>&1 & + MONITOR_PID=$! + log_ok "Guest monitor started (PID: $MONITOR_PID)" +fi + +# Start host trace capture +log_info "Starting host trace capture..." +sudo cat /sys/kernel/debug/tracing/trace_pipe > "$OUTPUT_DIR/host_trace.log" 2>&1 & +TRACE_PID=$! +log_ok "Host trace capture started (PID: $TRACE_PID)" + +# Save QEMU command +echo "${QEMU_CMD[@]}" > "$OUTPUT_DIR/qemu_cmd.txt" + +# Launch QEMU in background +log_info "Launching QEMU with GDB server on port $GDB_PORT..." +"${QEMU_CMD[@]}" > "$OUTPUT_DIR/qemu.log" 2>&1 & +QEMU_PID=$! +log_ok "QEMU started (PID: $QEMU_PID)" + +# Give QEMU time to start +sleep 3 + +# Launch GDB if vmlinux provided +if [[ -n "${VMLINUX:-}" && -f "$VMLINUX" ]]; then + log_info "Launching GDB with nvidia_init.gdb..." + log_info "GDB will connect to localhost:$GDB_PORT" + log_info "In GDB: (gdb) target remote localhost:$GDB_PORT" + log_info "Then: (gdb) continue" + + gdb -x "$BASE_DIR/tools/gdb_scripts/nvidia_init.gdb" "$VMLINUX" \ + -ex "target remote localhost:$GDB_PORT" \ + -ex "set logging file $OUTPUT_DIR/gdb.log" \ + -ex "set logging on" +else + log_warn "No vmlinux provided. Connect manually:" + log_warn " gdb -x $BASE_DIR/tools/gdb_scripts/nvidia_init.gdb /path/to/vmlinux" + log_warn " (gdb) target remote localhost:$GDB_PORT" + log_warn "" + log_warn "Press Ctrl+C to stop QEMU and monitoring..." + + # Wait for QEMU or interrupt + wait $QEMU_PID +fi + +# Cleanup +log_info "Cleaning up..." +[[ -n "$MONITOR_PID" ]] && kill $MONITOR_PID 2>/dev/null || true +[[ -n "$TRACE_PID" ]] && kill $TRACE_PID 2>/dev/null || true +kill $QEMU_PID 2>/dev/null || true + +log_info "Debug session complete. Logs in: $OUTPUT_DIR" +ls -la "$OUTPUT_DIR"
\ No newline at end of file diff --git a/scripts/launch_qemu_vgpu.sh b/scripts/launch_qemu_vgpu.sh new file mode 100755 index 0000000..2b64f63 --- /dev/null +++ b/scripts/launch_qemu_vgpu.sh @@ -0,0 +1,198 @@ +#!/bin/bash +# launch_qemu_vgpu.sh - Launch QEMU with NVIDIA vGPU mediated device +# Usage: ./launch_qemu_vgpu.sh [install|run] [MDEV_UUID] [GUEST_IMAGE] [OPTIONS] + +set -euo pipefail + +MODE="${1:-run}" +if [[ "$MODE" == "install" ]]; then + shift +elif [[ "$MODE" == "run" ]]; then + shift +else + # Default to run if first arg doesn't match + MODE="run" +fi + +MDEV_UUID="${1:-}" +GUEST_IMAGE="${2:-/var/lib/libvirt/images/ubuntu-22.04.qcow2}" +shift 2 || true +EXTRA_QEMU_ARGS=("$@") + +ISO_IMAGE="/var/lib/libvirt/images/ubuntu-24.04.5-live-server-amd64.iso" + +# Find mdev device if UUID not specified +if [[ -z "$MDEV_UUID" ]]; then + echo "Scanning for available mdev devices..." + mapfile -t MDEVS < <(find /sys/bus/mdev/devices -maxdepth 1 -name "????????-????-????-????-????????????" -printf "%f\n" 2>/dev/null) + if [[ ${#MDEVS[@]} -eq 0 ]]; then + echo "ERROR: No mdev devices found. Run create_mdev.sh first." + exit 1 + elif [[ ${#MDEVS[@]} -eq 1 ]]; then + MDEV_UUID="${MDEVS[0]}" + echo "Auto-selected mdev: $MDEV_UUID" + else + echo "Multiple mdev devices found:" + for i in "${!MDEVS[@]}"; do + MDEV="${MDEVS[$i]}" + TYPE=$(cat "/sys/bus/mdev/devices/$MDEV/mdev_type/name" 2>/dev/null || echo "unknown") + echo " [$i] $MDEV ($TYPE)" + done + read -p "Select mdev [0-$((${#MDEVS[@]}-1))]: " idx + MDEV_UUID="${MDEVS[$idx]}" + fi +fi + +MDEV_PATH="/sys/bus/mdev/devices/$MDEV_UUID" + +if [[ ! -d "$MDEV_PATH" ]]; then + echo "ERROR: mdev device $MDEV_UUID not found at $MDEV_PATH" + exit 1 +fi + +# Verify guest image +if [[ ! -f "$GUEST_IMAGE" ]]; then + echo "ERROR: Guest image not found: $GUEST_IMAGE" + echo "Create one with: qemu-img create -f qcow2 $GUEST_IMAGE 50G" + exit 1 +fi + +# Check KVM +if [[ ! -r /dev/kvm ]]; then + echo "ERROR: KVM not available (/dev/kvm not readable)" + exit 1 +fi + +# Check VFIO +if [[ ! -e /dev/vfio/vfio ]]; then + echo "ERROR: VFIO not available" + exit 1 +fi + +# Get mdev info +VGPU_TYPE=$(cat "$MDEV_PATH/mdev_type/name" 2>/dev/null || echo "unknown") +PCI_ADDR=$(readlink -f "$MDEV_PATH/../../.." | xargs basename) + +echo "==========================================" +echo "Launching QEMU with NVIDIA vGPU ($MODE mode)" +echo "==========================================" +echo "mdev UUID: $MDEV_UUID" +echo "vGPU Type: $VGPU_TYPE" +echo "PCI Addr: $PCI_ADDR" +echo "Guest Image: $GUEST_IMAGE" +echo "Extra Args: ${EXTRA_QEMU_ARGS[*]}" +echo "==========================================" + +# CPU configuration for vGPU +CPU_OPTS=( + -cpu host,hv_time,hv_relaxed,hv_vapic,hv_spinlocks=0x1fff,hv_vendor_id=NVIDIA42 + -smp 8,sockets=1,cores=8,threads=1 + -m 16G,slots=4,maxmem=64G + -mem-prealloc +) + +# Memory backing for hugepages (better performance) +HUGEPAGE_OPTS=( + -object memory-backend-file,id=mem,size=16G,mem-path=/dev/hugepages,share=on + -numa node,memdev=mem +) + +# VFIO device configuration +VFIO_OPTS=( + -device vfio-pci,sysfsdev="$MDEV_PATH",display=off +) + +# Display - use qxl-vga with GTK for local visible window +DISPLAY_OPTS=( + -device qxl-vga + -display gtk +) + +# Network +NET_OPTS=( + -netdev user,id=net0,hostfwd=tcp::2222-:22 + -device virtio-net-pci,netdev=net0 +) + +# Storage +if [[ "$MODE" == "install" ]]; then + if [[ ! -f "$ISO_IMAGE" ]]; then + echo "ERROR: ISO image not found: $ISO_IMAGE" + exit 1 + fi + STORAGE_OPTS=( + -drive file="$GUEST_IMAGE",format=qcow2,if=virtio,cache=writeback,aio=threads + -drive file="$ISO_IMAGE",format=raw,if=virtio,media=cdrom + ) + echo "Installation mode: ISO attached ($ISO_IMAGE)" +else + STORAGE_OPTS=( + -drive file="$GUEST_IMAGE",format=qcow2,if=virtio,cache=writeback,aio=threads + ) + echo "Run mode: No ISO attached" +fi + +# USB tablet for better mouse integration +USB_OPTS=( + -usb + -device usb-tablet +) + +# RNG +RNG_OPTS=( + -object rng-random,id=rng0,filename=/dev/urandom + -device virtio-rng-pci,rng=rng0 +) + +# Serial log for debugging +SERIAL_OPTS=( + -serial file:/tmp/qemu-serial.log +) + +# QEMU command +QEMU_CMD=( + qemu-system-x86_64 + -enable-kvm + -machine q35,accel=kvm,kernel_irqchip=split + -bios /usr/share/ovmf/OVMF.fd + "${CPU_OPTS[@]}" + "${HUGEPAGE_OPTS[@]}" + "${VFIO_OPTS[@]}" + "${DISPLAY_OPTS[@]}" + "${NET_OPTS[@]}" + "${STORAGE_OPTS[@]}" + "${USB_OPTS[@]}" + "${RNG_OPTS[@]}" + "${SERIAL_OPTS[@]}" + "${EXTRA_QEMU_ARGS[@]}" + -name "vGPU-Guest-$VGPU_TYPE" + -pidfile "/tmp/qemu-vgpu-$MDEV_UUID.pid" + -daemonize +) + +echo "Starting QEMU..." +echo "Command: ${QEMU_CMD[*]}" +echo "" + +"${QEMU_CMD[@]}" + +sleep 3 + +if [[ -f "/tmp/qemu-vgpu-$MDEV_UUID.pid" ]]; then + PID=$(cat "/tmp/qemu-vgpu-$MDEV_UUID.pid") + if kill -0 "$PID" 2>/dev/null; then + echo "SUCCESS: QEMU started with PID $PID" + echo "" + echo "GTK window should be visible on your display" + echo "Connect via SSH: ssh -p 2222 user@localhost" + echo "" + echo "To stop: kill $PID" + echo "Serial log: /tmp/qemu-serial.log" + else + echo "ERROR: QEMU failed to start" + exit 1 + fi +else + echo "ERROR: QEMU PID file not created" + exit 1 +fi
\ No newline at end of file diff --git a/scripts/load_vgpu_stack.sh b/scripts/load_vgpu_stack.sh new file mode 100755 index 0000000..fcabb06 --- /dev/null +++ b/scripts/load_vgpu_stack.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# load_vgpu_stack.sh - Load complete vGPU driver stack +# Usage: ./load_vgpu_stack.sh [firmware_name] + +set -euo pipefail + +FIRMWARE_NAME="${1:-gsp-570.144.fwimage.bin}" + +BASE_DIR="${OPEN_IOV_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +NVIDIA_KO="$BASE_DIR/nvidia-open-gpu-kernel-modules/kernel-open/nvidia.ko" +VFIO_KO="$BASE_DIR/kernel/open-iov-vfio.ko" +FIRMWARE_PATH="$BASE_DIR/firmware/57X-GSP/570.144/$FIRMWARE_NAME" + +echo "==========================================" +echo "Loading vGPU Driver Stack (Refactored: Host-only GSP Emulation)" +echo "==========================================" +echo "Firmware: $FIRMWARE_NAME" +echo "" + +# Check files exist +for f in "$NVIDIA_KO" "$VFIO_KO" "$FIRMWARE_PATH"; do + if [[ ! -f "$f" ]]; then + echo "ERROR: Missing file: $f" + exit 1 + fi +done + +# Load open-iov-vfio.ko FIRST (provides symbols nvidia.ko needs) +if lsmod | grep -q "^open_iov_vfio "; then + echo "open-iov-vfio.ko already loaded" +else + echo "Loading open-iov-vfio.ko..." + sudo insmod "$VFIO_KO" + echo " OK" +fi + +# Check if already loaded +if lsmod | grep -q "^nvidia "; then + echo "nvidia.ko already loaded" +else + echo "Loading nvidia.ko (OpenRM)..." + sudo insmod "$NVIDIA_KO" + echo " OK" +fi + +echo "" +echo "==========================================" +echo "Driver Stack Loaded Successfully" +echo "==========================================" +lsmod | grep -E "nvidia|open_iov" +echo "" +echo "Device nodes:" +ls -la /dev/nvidia* 2>/dev/null || echo " (none yet - create mdev first)" +echo "" +echo "Next steps:" +echo " 1. Create mdev: $BASE_DIR/scripts/create_mdev.sh" +echo " 2. Launch QEMU: $BASE_DIR/scripts/launch_qemu_vgpu.sh"
\ No newline at end of file diff --git a/scripts/qemu_gdb_attach.sh b/scripts/qemu_gdb_attach.sh new file mode 100644 index 0000000..310c196 --- /dev/null +++ b/scripts/qemu_gdb_attach.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# qemu_gdb_attach.sh - Launch QEMU with GDB server for guest kernel debugging +# Usage: ./qemu_gdb_attach.sh [gdb_port] [freeze_at_start] + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BASE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +GDB_PORT="${1:-1234}" +FREEZE="${2:-true}" # -S flag to freeze at startup + +# Default QEMU command from launch_qemu_vgpu.sh +QEMU_CMD=( + qemu-system-x86_64 + -enable-kvm + -cpu host + -smp 4 + -m 8G + -device vfio-pci,sysfsdev=/sys/bus/mdev/devices/$(cat /sys/bus/mdev/devices/*/uuid 2>/dev/null | head -1),display=off + -drive file=/var/lib/libvirt/images/ubuntu-vgpu.qcow2,format=qcow2,if=virtio + -netdev user,id=net0,hostfwd=tcp::2222-:22 + -device virtio-net-pci,netdev=net0 + -nographic + -serial mon:stdio +) + +# Add GDB server options +if [[ "$FREEZE" == "true" ]]; then + QEMU_CMD+=(-s -S) # -s = gdbserver on :1234, -S = freeze at startup +else + QEMU_CMD+=(-s) # -s = gdbserver on :1234, run normally +fi + +# Override port if specified +if [[ "$GDB_PORT" != "1234" ]]; then + QEMU_CMD+=(-gdb "tcp::$GDB_PORT") +fi + +echo "==========================================" +echo "QEMU GDB Debug Launch" +echo "==========================================" +echo "GDB Port: $GDB_PORT" +echo "Freeze at start: $FREEZE" +echo "QEMU Command: ${QEMU_CMD[*]}" +echo "" +echo "In another terminal, connect with:" +echo " gdb ./vmlinux" +echo " (gdb) target remote localhost:$GDB_PORT" +echo " (gdb) break nvidia_probe" +echo " (gdb) continue" +echo "" +echo "Or use the GDB script:" +echo " gdb -x $BASE_DIR/tools/gdb_scripts/nvidia_init.gdb ./vmlinux" +echo "" + +# Launch QEMU +exec "${QEMU_CMD[@]}"
\ No newline at end of file diff --git a/scripts/setup_guest_driver.sh b/scripts/setup_guest_driver.sh new file mode 100755 index 0000000..f4f2757 --- /dev/null +++ b/scripts/setup_guest_driver.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# setup_guest_driver.sh - Setup NVIDIA driver in QEMU guest +# Run this INSIDE the guest VM after installation + +set -euo pipefail + +echo "==========================================" +echo "Setting up NVIDIA driver in guest" +echo "==========================================" + +# Check if running as root +if [[ $EUID -ne 0 ]]; then + echo "ERROR: This script must be run as root" + exit 1 +fi + +# Check kernel version +KERNEL_VER=$(uname -r) +echo "Kernel: $KERNEL_VER" + +# Install dependencies +echo "Installing build dependencies..." +apt-get update +apt-get install -y \ + build-essential \ + dkms \ + linux-headers-"$KERNEL_VER" \ + linux-headers-generic \ + pciutils \ + clinfo + +# Check for NVIDIA GPU in guest +echo "Checking for NVIDIA GPU in guest..." +lspci -d 10de: | grep -E "VGA|3D controller" || { + echo "WARNING: No NVIDIA GPU detected in guest" + echo "Make sure QEMU is started with -device vfio-pci,sysfsdev=..." +} + +# Option 1: Install from Ubuntu repository (easiest) +echo "" +echo "Choose installation method:" +echo " 1) Ubuntu repository (nvidia-driver-550-open)" +echo " 2) NVIDIA runfile (latest)" +echo " 3) Build from source (open-gpu-kernel-modules)" +read -p "Select [1-3]: " choice + +case $choice in + 1) + echo "Installing from Ubuntu repository..." + apt-get install -y nvidia-driver-550-open + ;; + 2) + echo "Downloading NVIDIA runfile..." + RUNFILE="NVIDIA-Linux-x86_64-570.144.run" + wget -q "https://us.download.nvidia.com/XFree86/Linux-x86_64/570.144/$RUNFILE" + chmod +x "$RUNFILE" + ./"$RUNFILE" --silent --dkms --no-opengl-files + ;; + 3) + echo "Building from open-gpu-kernel-modules source..." + git clone https://github.com/NVIDIA/open-gpu-kernel-modules.git /tmp/open-gpu-kernel-modules + cd /tmp/open-gpu-kernel-modules + git checkout 570.144 + make -C kernel-open/modules SYSSRC=/usr/src/linux-headers-"$KERNEL_VER" -j$(nproc) + make -C kernel-open/modules SYSSRC=/usr/src/linux-headers-"$KERNEL_VER" modules_install + depmod -a + ;; + *) + echo "Invalid choice" + exit 1 + ;; +esac + +# Install firmware +echo "Installing GSP firmware..." +mkdir -p /lib/firmware/nvidia/tu102/gsp +# Firmware files should be copied from host or downloaded +# For TU104 (Turing), we need: +# - bootloader-535.113.01.bin +# - booter_load-535.113.01.bin +# - gsp-535.113.01.bin +echo "Copy firmware files to /lib/firmware/nvidia/tu102/gsp/" +echo " (bootloader, booter_load, gsp binaries)" + +# Load driver +echo "Loading NVIDIA driver..." +modprobe nvidia + +# Verify +echo "" +echo "==========================================" +echo "Verification" +echo "==========================================" +nvidia-smi +echo "" +dmesg -T | grep -i nvidia | tail -20 + +echo "" +echo "Setup complete! Recommended: reboot the guest"
\ No newline at end of file diff --git a/scripts/stack_manager.sh b/scripts/stack_manager.sh new file mode 100755 index 0000000..faf345b --- /dev/null +++ b/scripts/stack_manager.sh @@ -0,0 +1,437 @@ +#!/bin/bash +# stack_manager.sh - Complete vGPU stack management (load, unload, test, debug) +# Usage: ./stack_manager.sh <command> [options] + +set -euo pipefail + +BASE_DIR="${OPEN_IOV_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +NVIDIA_KO="$BASE_DIR/nvidia-open-gpu-kernel-modules/kernel-open/nvidia.ko" +VFIO_KO="$BASE_DIR/kernel/open-iov-vfio.ko" +FIRMWARE_PATH="$BASE_DIR/firmware/57X-GSP/570.144/gsp-570.144.fwimage.bin" +FIRMWARE_DEST="/lib/firmware/gsp-570.144.fwimage.bin" + +MDEV_SCRIPT="$BASE_DIR/scripts/create_mdev.sh" +# Legacy direct-QEMU script retained for reference only - VM launch MUST go +# through the harness (vgpu_vm.py). See cmd_launch_qemu. +QEMU_SCRIPT="$BASE_DIR/scripts/launch_qemu_vgpu.sh" +TEST_SCRIPT="$BASE_DIR/scripts/test_vgpu_stack.sh" + +color_red='\033[0;31m' +color_green='\033[0;32m' +color_yellow='\033[1;33m' +color_blue='\033[0;34m' +color_nc='\033[0m' + +log_info() { echo -e "${color_blue}[INFO]${color_nc} $*"; } +log_ok() { echo -e "${color_green}[OK]${color_nc} $*"; } +log_warn() { echo -e "${color_yellow}[WARN]${color_nc} $*"; } +log_err() { echo -e "${color_red}[ERROR]${color_nc} $*"; } + +# ============================================================ +# BUILD COMMANDS (correct order matters!) +# ============================================================ + +cmd_build_kernel() { + log_info "Building open-iov-vfio.ko (kernel module)..." + cd "$BASE_DIR" + make kernel + log_ok "open-iov-vfio.ko built" +} + +cmd_build_nvidia() { + log_info "Building NVIDIA OpenRM with vGPU symbols (KBUILD_EXTRA_SYMBOLS)..." + cd "$BASE_DIR" + + # Step 1: Build nvidia kernel module (nv-kernel.o) + log_info "Building nvidia kernel module (nv-kernel.o)..." + cd "$BASE_DIR/nvidia-open-gpu-kernel-modules/src/nvidia" + make -j$(nproc) + log_ok "nvidia kernel module built" + + # Step 2: Build nvidia-modeset kernel module (nv-modeset-kernel.o) + log_info "Building nvidia-modeset kernel module (nv-modeset-kernel.o)..." + cd "$BASE_DIR/nvidia-open-gpu-kernel-modules/src/nvidia-modeset" + make -j$(nproc) + log_ok "nvidia-modeset kernel module built" + + # Step 3: Build kernel-open modules with KBUILD_EXTRA_SYMBOLS + log_info "Building kernel-open modules with KBUILD_EXTRA_SYMBOLS..." + cd "$BASE_DIR/nvidia-open-gpu-kernel-modules/kernel-open" + KBUILD_EXTRA_SYMBOLS="$BASE_DIR/kernel/Module.symvers" make -j$(nproc) modules + log_ok "NVIDIA OpenRM built" +} + +cmd_build_userspace() { + log_info "Building userspace (libiov.so + examples)..." + cd "$BASE_DIR" + make userspace + make examples + log_ok "Userspace built" +} + +cmd_build_all() { + log_info "=== BUILD ALL (correct order) ===" + cmd_build_kernel + cmd_build_userspace + log_ok "=== ALL BUILDS COMPLETE ===" + log_info "NOTE: NVIDIA submodule (610-based) NOT built by default." + log_info " Only needed for NVIDIA's native vGPU management (not QEMU)." + log_info " Build separately with: stack_manager.sh build-nvidia" +} + +# ============================================================ +# LOAD COMMANDS (correct order matters!) +# ============================================================ + +cmd_load_prereqs() { + log_info "Loading kernel prerequisites (vfio, mdev)..." + # vfio_mdev does not exist on kernels >= 6.4 (mdev core is standalone mdev.ko); + # modprobe each individually so a missing one never blocks the rest. + local m + for m in vfio vfio_iommu_type1 vfio_pci mdev vfio_mdev; do + if modinfo "$m" &>/dev/null; then + sudo modprobe "$m" 2>/dev/null || true + fi + done + lsmod | grep -E "vfio|mdev" +} + +cmd_load_open_iov() { + if [[ ! -f "$VFIO_KO" ]]; then + log_err "Missing $VFIO_KO - run 'build' first" + return 1 + fi + if ! lsmod | grep -q "^open_iov_vfio "; then + log_info "Loading open-iov-vfio.ko..." + sudo insmod "$VFIO_KO" || { log_err "Failed to load open-iov-vfio.ko"; return 1; } + log_ok "open-iov-vfio.ko loaded" + else + log_ok "open-iov-vfio.ko already loaded" + fi +} + +cmd_load_nvidia() { + if [[ ! -f "$NVIDIA_KO" ]]; then + log_warn "NVIDIA submodule not built - skipping (apt nvidia works for host GPU)" + return 0 + fi + if lsmod | grep -q "^nvidia "; then + # A module named 'nvidia' is already loaded. For QEMU/vGPU with + # open-iov-vfio.ko (emulated VFIO device), we do NOT need our + # submodule nvidia.ko on the host - the apt nvidia driver manages + # the physical GPU and open-iov-vfio handles the emulated vGPU. + # Loading our submodule would conflict with the apt driver and + # potentially crash the GSP (WPR2 stuck). Skip it. + local loaded_ver + loaded_ver=$(cat /sys/module/nvidia/version 2>/dev/null) + log_ok "apt nvidia ($loaded_ver) already loaded - submodule not needed for QEMU" + return 0 + fi + log_info "Loading nvidia.ko (OpenRM)..." + sudo insmod "$NVIDIA_KO" || { log_err "Failed to load nvidia.ko"; return 1; } + log_ok "nvidia.ko loaded" +} + +cmd_install_firmware() { + if [[ ! -f "$FIRMWARE_PATH" ]]; then + log_err "Missing firmware at $FIRMWARE_PATH" + return 1 + fi + if [[ ! -f "$FIRMWARE_DEST" ]] || ! cmp -s "$FIRMWARE_PATH" "$FIRMWARE_DEST"; then + log_info "Installing firmware to $FIRMWARE_DEST..." + sudo cp "$FIRMWARE_PATH" "$FIRMWARE_DEST" + log_ok "Firmware installed" + else + log_ok "Firmware already installed" + fi +} + +cmd_load_stack() { + log_info "=== LOAD STACK (correct order) ===" + cmd_load_prereqs + cmd_load_open_iov + cmd_install_firmware + # NOTE: NVIDIA submodule NOT loaded for QEMU/vGPU work. + # apt nvidia (570.211.01) manages the physical GPU; + # open-iov-vfio handles the emulated vGPU. + log_ok "=== DRIVER STACK LOADED ===" + lsmod | grep -E "nvidia|open_iov|vfio|mdev" +} + +# Full cycle: build all + load stack + create mdev +cmd_up() { + log_info "=== FULL STARTUP: build + load + mdev ===" + cmd_build_all + cmd_load_stack + cmd_create_mdev + log_ok "=== SYSTEM READY FOR QEMU ===" + echo "Run: ./stack_manager.sh qemu" +} + +# ============================================================ +# UNLOAD COMMANDS +# ============================================================ + +cmd_unload_stack() { + log_info "=== UNLOAD STACK ===" + + if [[ -e /sys/bus/mdev/devices/* ]]; then + log_warn "MDEV devices exist - removing them first..." + for mdev in /sys/bus/mdev/devices/*; do + uuid=$(basename "$mdev") + log_info "Removing mdev $uuid..." + echo 1 | sudo tee "$mdev/remove" >/dev/null + done + sleep 2 + fi + + # Only unload OUR submodule nvidia.ko if it was loaded (not apt nvidia). + # The apt nvidia driver (e.g. 570.211.01) manages the physical GPU and + # must stay loaded for nvidia-smi to keep working. + if [[ -f "$NVIDIA_KO" ]] && lsmod | grep -q "^nvidia "; then + local loaded_ver want_ver + loaded_ver=$(cat /sys/module/nvidia/version 2>/dev/null) + want_ver=$(modinfo -F version "$NVIDIA_KO" 2>/dev/null) + if [[ -n "$loaded_ver" && "$loaded_ver" == "$want_ver" ]]; then + for mod in nvidia_uvm nvidia_modeset nvidia_drm nvidia_peermem nvidia; do + if lsmod | grep -qE "^$mod\>"; then + log_info "Unloading submodule $mod..." + sudo rmmod "$mod" || { log_err "Failed to unload $mod"; return 1; } + log_ok "$mod unloaded" + fi + done + else + log_ok "apt nvidia ($loaded_ver) kept loaded for host GPU" + fi + fi + + if lsmod | grep -qE "^open_iov_vfio\>"; then + log_info "Unloading open-iov-vfio.ko..." + sudo rmmod open_iov_vfio || { log_err "Failed to unload open-iov-vfio.ko"; return 1; } + log_ok "open-iov-vfio.ko unloaded" + fi + + sudo modprobe -r vfio_mdev vfio_pci vfio_iommu_type1 vfio mdev 2>/dev/null || true + log_ok "=== DRIVER STACK UNLOADED ===" +} + +# ============================================================ +# MDEV COMMANDS +# ============================================================ + +cmd_create_mdev() { + log_info "Creating mdev device..." + if [[ ! -f "$MDEV_SCRIPT" ]]; then + log_err "create_mdev.sh not found" + return 1 + fi + "$MDEV_SCRIPT" "$@" +} + +cmd_list_mdev() { + log_info "MDEV devices:" + ls -la /sys/bus/mdev/devices/ 2>/dev/null || log_warn "No mdev devices" +} + +# ============================================================ +# QEMU COMMANDS +# ============================================================ + +cmd_launch_qemu() { + # WORKFLOW RULE: always use the QEMU harness (vgpu_vm.py), never + # or raw QEMU directly - the harness owns , mdev lifecycle, QMP, + # guest-agent and serial logging. + local harness="$BASE_DIR/scripts/vgpu_vm.py" + if [[ ! -f "$harness" ]]; then + log_err "vgpu_vm.py harness not found at $harness" + return 1 + fi + log_info "Launching QEMU with vGPU via harness (vgpu_vm.py)..." + "$harness" start "${1:-vgpu-linux}" +} + +# ============================================================ +# TEST COMMANDS +# ============================================================ + +cmd_test_stack() { + log_info "Running comprehensive test suite..." + if [[ ! -f "$TEST_SCRIPT" ]]; then + log_err "test_vgpu_stack.sh not found" + return 1 + fi + "$TEST_SCRIPT" "$@" +} + +# ============================================================ +# STATUS / DEBUG +# ============================================================ + +cmd_status() { + echo "=== Kernel Modules ===" + lsmod | grep -E "nvidia|open_iov|vfio|mdev" || echo " (none)" + echo "" + echo "=== MDEV Devices ===" + ls -la /sys/bus/mdev/devices/ 2>/dev/null || echo " (none)" + echo "" + echo "=== VFIO Devices ===" + ls -la /dev/vfio/ 2>/dev/null || echo " (none)" + echo "" + echo "=== Firmware ===" + ls -la "$FIRMWARE_DEST" 2>/dev/null || echo " Not installed" + echo "" + echo "=== dmesg (last 20) ===" + sudo dmesg -T | grep -i -e nvidia -e gsp -e vgpu -e open-iov -e mdev | tail -20 +} + +cmd_dmesg() { + sudo dmesg -T -w | grep -i -e nvidia -e gsp -e vgpu -e open-iov -e mdev +} + +cmd_debug_qemu() { + # WORKFLOW RULE: harness only. The vgpu-linux.yaml already sets + # serialLog=/tmp/vgpu-guest-serial.log and gdbPort=1234, so a normal + # harness start IS the debug session: attach GDB with + # gdb -ex 'target remote localhost:1234' + # and follow the guest serial log plus host dmesg. + local harness="$BASE_DIR/scripts/vgpu_vm.py" + if [[ ! -f "$harness" ]]; then + log_err "vgpu_vm.py harness not found at $harness" + return 1 + fi + log_info "Starting debug session via harness (GDB stub tcp::1234, serial /tmp/vgpu-guest-serial.log)..." + "$harness" start "${1:-vgpu-linux}" + log_info "Attach GDB: gdb -ex 'target remote localhost:1234'" + log_info "Serial log: tail -f /tmp/vgpu-guest-serial.log" +} + +cmd_cleanup_crash() { + log_info "Cleaning up after crash..." + cmd_unload_stack + log_info "Clearing any stuck mdev devices..." + for mdev in /sys/bus/mdev/devices/*; do + [[ -e "$mdev" ]] || continue + uuid=$(basename "$mdev") + echo 1 | sudo tee "$mdev/remove" >/dev/null 2>&1 || true + done + log_ok "Cleanup complete" +} + +# ============================================================ +# HELP +# ============================================================ + +cmd_help() { + cat <<EOF +stack_manager.sh - Complete vGPU Stack Management + +USAGE: + ./stack_manager.sh <command> [options] + +BUILD COMMANDS (run in order): + build-kernel Build open-iov-vfio.ko (generates Module.symvers) + build-nvidia Build NVIDIA OpenRM with KBUILD_EXTRA_SYMBOLS + build-userspace Build libiov.so + examples + build-all Run all three build steps in correct order + +LOAD COMMANDS (run in order): + load-prereqs Load vfio, vfio_iommu_type1, vfio_pci, mdev, vfio_mdev + load-open-iov Load open-iov-vfio.ko + load-nvidia Load nvidia.ko (OpenRM) + install-firmware Copy GSP firmware to /lib/firmware/ + load-stack Run all four load steps in correct order + +FULL CYCLE: + up Build all + load stack + create mdev (one command!) + +MDEV COMMANDS: + mdev-create Create mdev device + mdev-list List mdev devices + +QEMU COMMANDS: + qemu Launch QEMU with vGPU + qemu-debug Launch QEMU with GDB + guest monitor + +TEST COMMANDS: + test Run comprehensive test suite + +STATUS / DEBUG: + status Show current stack status + dmesg Follow filtered dmesg output + cleanup-crash Emergency cleanup after crash/hang + help Show this help + +EXAMPLES: + # Full startup from clean state: + ./stack_manager.sh up + + # Step by step: + ./stack_manager.sh build-all + ./stack_manager.sh load-stack + ./stack_manager.sh mdev-create + ./stack_manager.sh qemu + + # Or just load (if already built): + ./stack_manager.sh load-stack + ./stack_manager.sh mdev-create + ./stack_manager.sh qemu + + # Testing: + ./stack_manager.sh test + + # Cleanup: + ./stack_manager.sh unload + # Or force cleanup after crash: + ./stack_manager.sh cleanup-crash + +NOTE: + - Requires root for module operations + - BUILD ORDER: open-iov-vfio.ko FIRST (generates Module.symvers), + THEN nvidia.ko with KBUILD_EXTRA_SYMBOLS + - LOAD ORDER: vfio/mdev prerequisites -> open-iov-vfio.ko -> nvidia.ko + - UNLOAD ORDER: remove mdevs -> open-iov-vfio.ko -> nvidia.ko + - NEVER REBOOT without explicit approval +EOF +} + +main() { + case "${1:-help}" in + # Build + build-kernel) cmd_build_kernel ;; + build-nvidia) cmd_build_nvidia ;; + build-userspace) cmd_build_userspace ;; + build-all) cmd_build_all ;; + + # Load + load-prereqs) cmd_load_prereqs ;; + load-open-iov) cmd_load_open_iov ;; + load-nvidia) cmd_load_nvidia ;; + install-firmware) cmd_install_firmware ;; + load-stack) cmd_load_stack ;; + + # Full cycle + up) cmd_up ;; + + # Unload + unload) cmd_unload_stack ;; + + # MDEV + mdev-create) shift; cmd_create_mdev "$@" ;; + mdev-list) cmd_list_mdev ;; + + # QEMU + qemu) shift; cmd_launch_qemu "$@" ;; + qemu-debug) shift; cmd_debug_qemu "$@" ;; + + # Test + test) shift; cmd_test_stack "$@" ;; + + # Status/Debug + status) cmd_status ;; + dmesg) cmd_dmesg ;; + cleanup-crash) cmd_cleanup_crash ;; + help|*) cmd_help ;; + esac +} + +main "$@"
\ No newline at end of file diff --git a/scripts/test_cuda_workloads.sh b/scripts/test_cuda_workloads.sh new file mode 100755 index 0000000..ba3663a --- /dev/null +++ b/scripts/test_cuda_workloads.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# CUDA Workload Validation +# Tests various CUDA workloads in the guest + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OPEN_IOV_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +echo "=== CUDA Workload Validation ===" +echo "Open-IOV root: $OPEN_IOV_ROOT" + +# Check if we're root +if [ "$EUID" -ne 0 ]; then + echo "ERROR: This script must be run as root" + exit 1 +fi + +# This script assumes guest is already running with SSH on port 2222 +# and NVIDIA driver is installed + +GUEST_SSH="ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@localhost -p 2222" + +echo "Testing CUDA samples..." +$GUEST_SSH "cd /usr/local/cuda/samples && find . -name 'Makefile' -execdir make \\; 2>&1 | tail -20" + +echo "Running vectorAdd..." +$GUEST_SSH "cd /usr/local/cuda/samples/1_Utilities/vectorAdd && ./vectorAdd" + +echo "Running matrixMul..." +$GUEST_SSH "cd /usr/local/cuda/samples/0_Simple/matrixMul && ./matrixMul" + +echo "Running simpleCUBLAS..." +$GUEST_SSH "cd /usr/local/cuda/samples/7_CUDALibraries/simpleCUBLAS && ./simpleCUBLAS" + +echo "Running simpleCUFFT..." +$GUEST_SSH "cd /usr/local/cuda/samples/7_CUDALibraries/simpleCUFFT && ./simpleCUFFT" + +echo "Running deviceQuery..." +$GUEST_SSH "cd /usr/local/cuda/samples/1_Utilities/deviceQuery && ./deviceQuery" + +echo "Running bandwidthTest..." +$GUEST_SSH "cd /usr/local/cuda/samples/1_Utilities/bandwidthTest && ./bandwidthTest" + +echo "=== CUDA Workload Validation Complete ==="
\ No newline at end of file diff --git a/scripts/test_graphics_workloads.sh b/scripts/test_graphics_workloads.sh new file mode 100755 index 0000000..b3a873a --- /dev/null +++ b/scripts/test_graphics_workloads.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Graphics Workload Validation +# Tests Vulkan/OpenGL/video workloads in the guest + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OPEN_IOV_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +echo "=== Graphics Workload Validation ===" +echo "Open-IOV root: $OPEN_IOV_ROOT" + +# Check if we're root +if [ "$EUID" -ne 0 ]; then + echo "ERROR: This script must be run as root" + exit 1 +fi + +GUEST_SSH="ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@localhost -p 2222" + +echo "Testing Vulkan..." +$GUEST_SSH "vulkaninfo | head -50" +$GUEST_SSH "vkcube --duration 5" || echo "vkcube not available or failed" + +echo "Testing OpenGL..." +$GUEST_SSH "glxinfo | grep -i nvidia" +$GUEST_SSH "glxgears -info" || echo "glxgears not available" + +echo "Testing video encode/decode..." +$GUEST_SSH "ffmpeg -encoders | grep nvenc" || echo "NVENC not available" +$GUEST_SSH "ffmpeg -decoders | grep nvdec" || echo "NVDEC not available" + +echo "=== Graphics Workload Validation Complete ==="
\ No newline at end of file diff --git a/scripts/test_gsp_emu.sh b/scripts/test_gsp_emu.sh new file mode 100755 index 0000000..1f6bc6f --- /dev/null +++ b/scripts/test_gsp_emu.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# GSP Emulation Unit Tests +# Runs kernel module tests for GSP emulation engine + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OPEN_IOV_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +KERNEL_TEST_DIR="$OPEN_IOV_ROOT/kernel/tests" + +echo "=== GSP Emulation Unit Tests ===" +echo "Open-IOV root: $OPEN_IOV_ROOT" +echo "Kernel test dir: $KERNEL_TEST_DIR" + +# Check if we're root +if [ "$EUID" -ne 0 ]; then + echo "ERROR: This script must be run as root" + exit 1 +fi + +# Build the test module +echo "Building GSP emulation test module..." +cd "$KERNEL_TEST_DIR" +make clean +make + +if [ ! -f gsp_emulation_test.ko ]; then + echo "ERROR: Failed to build gsp_emulation_test.ko" + exit 1 +fi + +echo "Test module built successfully" + +# Load the test module +echo "Loading test module..." +insmod gsp_emulation_test.ko + +# Check dmesg for test results +sleep 2 +echo "=== Test Results ===" +dmesg -T | grep -i "gsp_emu_test" | tail -30 + +# Check if tests passed +if dmesg -T | grep -q "GSP_EMU_TEST: ALL TESTS PASSED"; then + echo "✓ ALL TESTS PASSED" + RESULT=0 +elif dmesg -T | grep -q "GSP_EMU_TEST:.*TEST.S. FAILED"; then + echo "✗ SOME TESTS FAILED" + RESULT=1 +else + echo "? TEST RESULT UNKNOWN" + RESULT=2 +fi + +# Unload test module +echo "Unloading test module..." +rmmod gsp_emulation_test 2>/dev/null || true + +exit $RESULT
\ No newline at end of file diff --git a/scripts/test_guest_driver.sh b/scripts/test_guest_driver.sh new file mode 100755 index 0000000..f391d64 --- /dev/null +++ b/scripts/test_guest_driver.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# Guest Driver Validation Suite +# Tests the guest NVIDIA driver with vGPU + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OPEN_IOV_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +echo "=== Guest Driver Validation Suite ===" +echo "Open-IOV root: $OPEN_IOV_ROOT" + +# Check if we're root +if [ "$EUID" -ne 0 ]; then + echo "ERROR: This script must be run as root" + exit 1 +fi + +# Check if mdev exists +MDEV_DEVICES=$(ls /sys/bus/mdev/devices/ 2>/dev/null | wc -l) +if [ "$MDEV_DEVICES" -eq 0 ]; then + echo "ERROR: No mdev devices found. Run create_mdev.sh first." + exit 1 +fi + +echo "Found $MDEV_DEVICES mdev device(s)" + +# Launch QEMU with vGPU +echo "Launching QEMU with vGPU..." +"$SCRIPT_DIR/launch_qemu_vgpu.sh" & +QEMU_PID=$! + +# Wait for QEMU to start +sleep 10 + +# Check if QEMU is running +if ! kill -0 $QEMU_PID 2>/dev/null; then + echo "ERROR: QEMU failed to start" + exit 1 +fi + +echo "QEMU started with PID $QEMU_PID" +echo "Guest should be booting..." + +# Wait for guest to boot and SSH to be available +echo "Waiting for guest SSH (timeout 120s)..." +for i in {1..24}; do + if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@localhost -p 2222 "echo 'SSH ready'" 2>/dev/null; then + echo "Guest SSH is ready" + break + fi + sleep 5 +done + +# Run guest driver setup +echo "Setting up guest NVIDIA driver..." +ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@localhost -p 2222 \ + "bash -s" < "$SCRIPT_DIR/setup_guest_driver.sh" + +# Test nvidia-smi +echo "Testing nvidia-smi..." +ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@localhost -p 2222 \ + "nvidia-smi" + +# Test CUDA +echo "Testing CUDA vectorAdd..." +ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@localhost -p 2222 \ + "cd /usr/local/cuda/samples/1_Utilities/vectorAdd && make && ./vectorAdd" + +# Cleanup +echo "Shutting down QEMU..." +kill $QEMU_PID 2>/dev/null || true +wait $QEMU_PID 2>/dev/null || true + +echo "=== Guest Driver Validation Complete ==="
\ No newline at end of file diff --git a/scripts/test_vgpu_stack.sh b/scripts/test_vgpu_stack.sh new file mode 100755 index 0000000..4df9cdc --- /dev/null +++ b/scripts/test_vgpu_stack.sh @@ -0,0 +1,149 @@ +#!/bin/bash +# Comprehensive Test Suite for Open-IOV vGPU-IO +# Runs all validation tests in sequence + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OPEN_IOV_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +echo "=== Open-IOV vGPU-IO Comprehensive Test Suite ===" +echo "Open-IOV root: $OPEN_IOV_ROOT" +echo "Date: $(date)" +echo "" + +# Check if we're root +if [ "$EUID" -ne 0 ]; then + echo "ERROR: This script must be run as root" + exit 1 +fi + +# Parse arguments +RUN_KERNEL_TESTS=true +RUN_GUEST_TESTS=true +RUN_CUDA_TESTS=true +RUN_GRAPHICS_TESTS=true +RUN_WINDOWS_TESTS=false + +while [[ $# -gt 0 ]]; do + case $1 in + --kernel-only) + RUN_GUEST_TESTS=false + RUN_CUDA_TESTS=false + RUN_GRAPHICS_TESTS=false + shift + ;; + --guest-only) + RUN_KERNEL_TESTS=false + RUN_CUDA_TESTS=false + RUN_GRAPHICS_TESTS=false + shift + ;; + --no-windows) + RUN_WINDOWS_TESTS=false + shift + ;; + --windows) + RUN_WINDOWS_TESTS=true + shift + ;; + *) + echo "Unknown option: $1" + echo "Usage: $0 [--kernel-only] [--guest-only] [--no-windows] [--windows]" + exit 1 + ;; + esac +done + +RESULTS=() + +# Test 1: Kernel GSP Emulation Tests +if [ "$RUN_KERNEL_TESTS" = true ]; then + echo "" + echo "========================================" + echo "TEST 1: Kernel GSP Emulation Unit Tests" + echo "========================================" + if "$SCRIPT_DIR/test_gsp_emu.sh"; then + RESULTS+=("Kernel GSP Emulation: PASS") + else + RESULTS+=("Kernel GSP Emulation: FAIL") + fi +fi + +# Test 2: Guest Driver Integration +if [ "$RUN_GUEST_TESTS" = true ]; then + echo "" + echo "========================================" + echo "TEST 2: Guest Driver Integration" + echo "========================================" + if "$SCRIPT_DIR/test_guest_driver.sh"; then + RESULTS+=("Guest Driver Integration: PASS") + else + RESULTS+=("Guest Driver Integration: FAIL") + fi +fi + +# Test 3: CUDA Workloads +if [ "$RUN_CUDA_TESTS" = true ]; then + echo "" + echo "========================================" + echo "TEST 3: CUDA Workload Validation" + echo "========================================" + if "$SCRIPT_DIR/test_cuda_workloads.sh"; then + RESULTS+=("CUDA Workloads: PASS") + else + RESULTS+=("CUDA Workloads: FAIL") + fi +fi + +# Test 4: Graphics Workloads +if [ "$RUN_GRAPHICS_TESTS" = true ]; then + echo "" + echo "========================================" + echo "TEST 4: Graphics Workload Validation" + echo "========================================" + if "$SCRIPT_DIR/test_graphics_workloads.sh"; then + RESULTS+=("Graphics Workloads: PASS") + else + RESULTS+=("Graphics Workloads: FAIL") + fi +fi + +# Test 5: Windows Guest (optional) +if [ "$RUN_WINDOWS_TESTS" = true ]; then + echo "" + echo "========================================" + echo "TEST 5: Windows Guest Validation" + echo "========================================" + if "$SCRIPT_DIR/test_windows_guest.sh"; then + RESULTS+=("Windows Guest: PASS") + else + RESULTS+=("Windows Guest: FAIL") + fi +fi + +# Summary +echo "" +echo "========================================" +echo "TEST SUMMARY" +echo "========================================" +for result in "${RESULTS[@]}"; do + echo " $result" +done + +# Check for failures +FAIL_COUNT=0 +for result in "${RESULTS[@]}"; do + if [[ "$result" == *"FAIL"* ]]; then + FAIL_COUNT=$((FAIL_COUNT + 1)) + fi +done + +echo "" +if [ $FAIL_COUNT -eq 0 ]; then + echo "ALL TESTS PASSED ✓" + exit 0 +else + echo "$FAIL_COUNT TEST(S) FAILED ✗" + exit 1 +fi
\ No newline at end of file diff --git a/scripts/test_windows_guest.sh b/scripts/test_windows_guest.sh new file mode 100755 index 0000000..7876bf4 --- /dev/null +++ b/scripts/test_windows_guest.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Windows Guest Validation +# Tests Windows guest with NVIDIA driver + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OPEN_IOV_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +echo "=== Windows Guest Validation ===" +echo "Open-IOV root: $OPEN_IOV_ROOT" + +# Check if we're root +if [ "$EUID" -ne 0 ]; then + echo "ERROR: This script must be run as root" + exit 1 +fi + +# This script assumes Windows guest is running with WinRM or SSH +# For now, this is a placeholder for the Windows test automation + +echo "Windows guest validation requires:" +echo " - Windows 10/11 guest with WinRM enabled" +echo " - NVIDIA 570.144 driver installed" +echo " - Test scripts copied to guest" + +echo "Test items (manual for now):" +echo " 1. Device Manager: Verify 'NVIDIA T4' (or equivalent) with Code 0" +echo " 2. nvidia-smi.exe: Shows vGPU info" +echo " 3. CUDA-Z: Device query passes" +echo " 4. vectorAdd.exe: Executes correctly" +echo " 5. dxdiag: Shows correct GPU info" +echo " 6. D3D11/D3D12/Vulkan: Render test passes" +echo " 7. NVENC/NVDEC: Encode/decode test passes" + +echo "=== Windows Guest Validation (Placeholder) ==="
\ No newline at end of file diff --git a/scripts/unload_vgpu_stack.sh b/scripts/unload_vgpu_stack.sh new file mode 100755 index 0000000..e02474a --- /dev/null +++ b/scripts/unload_vgpu_stack.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# unload_vgpu_stack.sh - Unload vGPU driver stack + +set -euo pipefail + +BASE_DIR="${OPEN_IOV_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" + +echo "==========================================" +echo "Unloading vGPU Driver Stack" +echo "==========================================" + +# Remove mdev devices first +echo "Removing mdev devices..." +for mdev in /sys/bus/mdev/devices/*/; do + if [[ -d "$mdev" ]]; then + UUID=$(basename "$mdev") + echo " Removing $UUID" + echo 1 | sudo tee "$mdev/remove" > /dev/null 2>&1 || true + fi +done + +# Unload modules in reverse order +for mod in gsp_vgpu open_iov_vfio nvidia; do + if lsmod | grep -q "^$mod "; then + echo "Unloading $mod.ko..." + sudo rmmod "$mod" 2>/dev/null || echo " WARNING: $mod still in use" + else + echo "$mod.ko not loaded" + fi +done + +echo "" +echo "==========================================" +echo "Driver Stack Unloaded" +echo "==========================================" +lsmod | grep -E "nvidia|open_iov|gsp_vgpu" || echo "No vGPU modules loaded"
\ No newline at end of file diff --git a/scripts/windows_guest_automation.sh b/scripts/windows_guest_automation.sh new file mode 100755 index 0000000..f95471e --- /dev/null +++ b/scripts/windows_guest_automation.sh @@ -0,0 +1,220 @@ +#!/bin/bash +# windows_guest_automation.sh - Windows guest test automation via WinRM/SSH + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BASE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +RESULTS_DIR="/tmp/gsp_emu_windows/$(date +%Y%m%d_%H%M%S)" +mkdir -p "$RESULTS_DIR" + +log_info() { echo -e "\033[0;34m[INFO]\033[0m $1"; } +log_ok() { echo -e "\033[0;32m[OK]\033[0m $1"; } +log_error() { echo -e "\033[0;31m[ERROR]\033[0m $1"; } + +# Configuration +WIN_USER="${WIN_USER:-Administrator}" +WIN_IP="${WIN_IP:-192.168.122.100}" +WIN_PASSWORD="${WIN_PASSWORD:-}" +WINRM_PORT="${WINRM_PORT:-5985}" +SSH_PORT="${SSH_PORT:-22}" + +check_winrm() { + log_info "Checking WinRM connectivity to $WIN_IP..." + if command -v winrm &>/dev/null; then + winrm identify -r:"http://$WIN_IP:$WINRM_PORT/wsman" -u:"$WIN_USER" -p:"$WIN_PASSWORD" -auth:basic 2>/dev/null + elif command -v python3 &>/dev/null; then + python3 -c " +import winrm +session = winrm.Session('$WIN_IP:$WINRM_PORT', auth=('$WIN_USER', '$WIN_PASSWORD'), transport='ntlm') +result = session.run_cmd('echo test') +print('WinRM OK' if result.status_code == 0 else 'WinRM FAILED') +" + else + log_error "No WinRM client found. Install winrm or python3 with pywinrm" + return 1 + fi +} + +run_winrm_cmd() { + local cmd="$1" + local output_file="$2" + + if command -v winrm &>/dev/null; then + winrm invoke -r:"http://$WIN_IP:$WINRM_PORT/wsman" -u:"$WIN_USER" -p:"$WIN_PASSWORD" \ + -auth:basic Create "http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Command" \ + "Command=cmd.exe" "Arguments=/c $cmd" > "$output_file" 2>&1 + else + python3 -c " +import winrm, sys +session = winrm.Session('$WIN_IP:$WINRM_PORT', auth=('$WIN_USER', '$WIN_PASSWORD'), transport='ntlm') +result = session.run_cmd('$cmd') +with open('$output_file', 'w') as f: + f.write(result.std_out.decode() + result.std_err.decode()) +sys.exit(result.status_code) +" + fi +} + +run_ssh_cmd() { + local cmd="$1" + local output_file="$2" + sshpass -p "$WIN_PASSWORD" ssh -o StrictHostKeyChecking=no -p "$SSH_PORT" "$WIN_USER@$WIN_IP" "$cmd" > "$output_file" 2>&1 +} + +test_nvidia_smi() { + log_info "Testing nvidia-smi..." + run_winrm_cmd "nvidia-smi" "$RESULTS_DIR/nvidia_smi.txt" + if grep -q "NVIDIA" "$RESULTS_DIR/nvidia_smi.txt"; then + log_ok "nvidia-smi: PASS" + return 0 + else + log_error "nvidia-smi: FAIL" + cat "$RESULTS_DIR/nvidia_smi.txt" + return 1 + fi +} + +test_cuda_vectoradd() { + log_info "Testing CUDA vectorAdd..." + run_winrm_cmd "cd C:\\cuda_samples\\1_Utilities\\vectorAdd && .\\vectorAdd.exe" "$RESULTS_DIR/cuda_vectoradd.txt" + if grep -q "Test passed" "$RESULTS_DIR/cuda_vectoradd.txt"; then + log_ok "CUDA vectorAdd: PASS" + return 0 + else + log_error "CUDA vectorAdd: FAIL" + cat "$RESULTS_DIR/cuda_vectoradd.txt" + return 1 + fi +} + +test_cuda_devquery() { + log_info "Testing CUDA deviceQuery..." + run_winrm_cmd "cd C:\\cuda_samples\\1_Utilities\\deviceQuery && .\\deviceQuery.exe" "$RESULTS_DIR/cuda_devquery.txt" + if grep -q "Result = PASS" "$RESULTS_DIR/cuda_devquery.txt"; then + log_ok "CUDA deviceQuery: PASS" + return 0 + else + log_error "CUDA deviceQuery: FAIL" + cat "$RESULTS_DIR/cuda_devquery.txt" + return 1 + fi +} + +test_vulkan() { + log_info "Testing Vulkan..." + run_winrm_cmd "vulkaninfo.exe" "$RESULTS_DIR/vulkaninfo.txt" + if grep -q "GPU id" "$RESULTS_DIR/vulkaninfo.txt"; then + log_ok "Vulkan: PASS" + return 0 + else + log_error "Vulkan: FAIL" + cat "$RESULTS_DIR/vulkaninfo.txt" + return 1 + fi +} + +test_dx12() { + log_info "Testing DirectX 12..." + run_winrm_cmd "dxdiag /t $RESULTS_DIR/dxdiag.txt" "$RESULTS_DIR/dxdiag_cmd.txt" + # Parse dxdiag output + if grep -q "Feature Level" "$RESULTS_DIR/dxdiag.txt"; then + log_ok "DirectX 12: PASS" + return 0 + else + log_error "DirectX 12: FAIL" + return 1 + fi +} + +test_ffmpeg_nvenc() { + log_info "Testing FFmpeg NVENC..." + run_winrm_cmd "ffmpeg -encoders" "$RESULTS_DIR/ffmpeg_encoders.txt" + if grep -q "h264_nvenc\|hevc_nvenc" "$RESULTS_DIR/ffmpeg_encoders.txt"; then + log_ok "FFmpeg NVENC: PASS" + return 0 + else + log_error "FFmpeg NVENC: FAIL" + return 1 + fi +} + +test_pytorch() { + log_info "Testing PyTorch..." + run_winrm_cmd "python -c \"import torch; print('CUDA:', torch.cuda.is_available()); print('Device:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'N/A')\"" "$RESULTS_DIR/pytorch.txt" + if grep -q "CUDA: True" "$RESULTS_DIR/pytorch.txt"; then + log_ok "PyTorch: PASS" + return 0 + else + log_error "PyTorch: FAIL" + cat "$RESULTS_DIR/pytorch.txt" + return 1 + fi +} + +test_windows_driver_signature() { + log_info "Checking driver signature status..." + run_winrm_cmd "pnputil /enum-drivers | findstr nvidia" "$RESULTS_DIR/driver_signature.txt" + cat "$RESULTS_DIR/driver_signature.txt" +} + +collect_event_logs() { + log_info "Collecting Windows event logs..." + run_winrm_cmd "wevtutil qe System /q:\"*[System[Provider[@Name='NVIDIA']]]\" /f:text /c:50" "$RESULTS_DIR/nvidia_events.txt" + run_winrm_cmd "wevtutil qe System /q:\"*[System[Provider[@Name='Display']]]\" /f:text /c:50" "$RESULTS_DIR/display_events.txt" +} + +run_full_suite() { + log_info "=== Windows Guest Test Suite ===" + local failed=0 + + test_nvidia_smi || ((failed++)) + test_cuda_devquery || ((failed++)) + test_cuda_vectoradd || ((failed++)) + test_vulkan || ((failed++)) + test_dx12 || ((failed++)) + test_ffmpeg_nvenc || ((failed++)) + test_pytorch || ((failed++)) + test_windows_driver_signature + collect_event_logs + + log_info "=== Results ===" + log_info "Failed tests: $failed" + + # Generate summary + cat > "$RESULTS_DIR/summary.json" <<EOF +{ + "timestamp": "$(date -Iseconds)", + "guest_ip": "$WIN_IP", + "failed_tests": $failed, + "tests": { + "nvidia_smi": $(test -f "$RESULTS_DIR/nvidia_smi.txt" && grep -q "NVIDIA" "$RESULTS_DIR/nvidia_smi.txt" && echo true || echo false), + "cuda_devquery": $(test -f "$RESULTS_DIR/cuda_devquery.txt" && grep -q "Result = PASS" "$RESULTS_DIR/cuda_devquery.txt" && echo true || echo false), + "cuda_vectoradd": $(test -f "$RESULTS_DIR/cuda_vectoradd.txt" && grep -q "Test passed" "$RESULTS_DIR/cuda_vectoradd.txt" && echo true || echo false), + "vulkan": $(test -f "$RESULTS_DIR/vulkaninfo.txt" && grep -q "GPU id" "$RESULTS_DIR/vulkaninfo.txt" && echo true || echo false), + "dx12": $(test -f "$RESULTS_DIR/dxdiag.txt" && grep -q "Feature Level" "$RESULTS_DIR/dxdiag.txt" && echo true || echo false), + "ffmpeg_nvenc": $(test -f "$RESULTS_DIR/ffmpeg_encoders.txt" && grep -q "h264_nvenc\|hevc_nvenc" "$RESULTS_DIR/ffmpeg_encoders.txt" && echo true || echo false), + "pytorch": $(test -f "$RESULTS_DIR/pytorch.txt" && grep -q "CUDA: True" "$RESULTS_DIR/pytorch.txt" && echo true || echo false) + } +} +EOF + + log_ok "Results saved to $RESULTS_DIR" + cat "$RESULTS_DIR/summary.json" +} + +main() { + case "${1:-full}" in + check) check_winrm ;; + nvidia-smi) test_nvidia_smi ;; + cuda) test_cuda_devquery && test_cuda_vectoradd ;; + graphics) test_vulkan && test_dx12 ;; + video) test_ffmpeg_nvenc ;; + pytorch) test_pytorch ;; + full) run_full_suite ;; + *) echo "Usage: $0 {check|nvidia-smi|cuda|graphics|video|pytorch|full}"; exit 1 ;; + esac +} + +main "$@"
\ No newline at end of file |
