summaryrefslogtreecommitdiffstats
path: root/tools/ghidra
diff options
context:
space:
mode:
authorOpen-IOV <dev@open-iov.org>2026-09-23 05:44:08 -0400
committerOpen-IOV <dev@open-iov.org>2026-09-23 05:46:43 -0400
commit2302fc09080bad51c73f293294e19fd4db464eb0 (patch)
treec722d186347fdef5a34131e9e143b1549b1daf8e /tools/ghidra
downloadopen-iov-2302fc09080bad51c73f293294e19fd4db464eb0.tar.gz
open-iov-2302fc09080bad51c73f293294e19fd4db464eb0.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 'tools/ghidra')
-rw-r--r--tools/ghidra/analyze_fwimage.py66
-rwxr-xr-xtools/ghidra/analyze_gsp_firmware.sh97
-rw-r--r--tools/ghidra/create_gsp_project.py67
-rw-r--r--tools/ghidra/diff_gsp_firmware.py220
-rw-r--r--tools/ghidra/gsp-fwimage-570.144/scripts/BasicAnalysis.java156
-rw-r--r--tools/ghidra/gsp-fwimage-570.144/scripts/DecompileFunctions.java88
-rw-r--r--tools/ghidra/gsp-fwimage-570.144/scripts/ExtractFunctions.java126
-rw-r--r--tools/ghidra/gsp-fwimage-570.144/scripts/basic_analysis.py108
-rw-r--r--tools/ghidra/gsp-tu104-570.144/scripts/DecompileFunctions.java143
-rw-r--r--tools/ghidra/gsp-tu104-570.144/scripts/analyze_gsp_fwimage.py207
-rw-r--r--tools/ghidra/gsp-tu104-570.144/scripts/basic_analysis.py108
-rw-r--r--tools/ghidra/gsp-tu104-570.144/scripts/extract_fwimage.py56
-rw-r--r--tools/ghidra/gsp-tu104-570.144/scripts/extract_gsp_version.py30
13 files changed, 1472 insertions, 0 deletions
diff --git a/tools/ghidra/analyze_fwimage.py b/tools/ghidra/analyze_fwimage.py
new file mode 100644
index 0000000..5d98504
--- /dev/null
+++ b/tools/ghidra/analyze_fwimage.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+"""
+Analyze GSP firmware .fwimage binary in Ghidra.
+Usage: python3 analyze_fwimage.py <fwimage_bin> <project_dir> <project_name>
+"""
+
+import sys
+import os
+import subprocess
+
+def analyze_fwimage(fwimage_path, project_dir, project_name):
+ """Analyze the .fwimage binary in Ghidra."""
+
+ ghidra_path = "/snap/bin/ghidra"
+ analyze_headless = "/snap/ghidra/47/ghidra/support/analyzeHeadless"
+
+ if not os.path.exists(analyze_headless):
+ analyze_headless = "/opt/ghidra/support/analyzeHeadless"
+
+ if not os.path.exists(analyze_headless):
+ print("ERROR: Ghidra analyzeHeadless not found")
+ return False
+
+ # Create project directory
+ os.makedirs(project_dir, exist_ok=True)
+
+ # Import the .fwimage binary
+ cmd = [
+ analyze_headless,
+ project_dir,
+ project_name,
+ "-import", fwimage_path,
+ "-processor", "RISCV:LE:64:default",
+ "-cspec", "gcc",
+ "-overwrite",
+ "-scriptPath", os.path.join(project_dir, "scripts"),
+ "-postScript", "analyze_gsp_fwimage.py"
+ ]
+
+ print(f"Running: {' '.join(cmd)}")
+ result = subprocess.run(cmd, capture_output=True, text=True, timeout=3600)
+
+ print(result.stdout)
+ if result.stderr:
+ print(result.stderr, file=sys.stderr)
+
+ return result.returncode == 0
+
+def main():
+ if len(sys.argv) < 4:
+ print("Usage: analyze_fwimage.py <fwimage_bin> <project_dir> <project_name>")
+ sys.exit(1)
+
+ fwimage_path = sys.argv[1]
+ project_dir = sys.argv[2]
+ project_name = sys.argv[3]
+
+ if not os.path.exists(fwimage_path):
+ print(f"ERROR: Firmware image not found: {fwimage_path}")
+ sys.exit(1)
+
+ success = analyze_fwimage(fwimage_path, project_dir, project_name)
+ sys.exit(0 if success else 1)
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/tools/ghidra/analyze_gsp_firmware.sh b/tools/ghidra/analyze_gsp_firmware.sh
new file mode 100755
index 0000000..b2e40d5
--- /dev/null
+++ b/tools/ghidra/analyze_gsp_firmware.sh
@@ -0,0 +1,97 @@
+#!/bin/bash
+# Full GSP firmware analysis pipeline
+# Usage: ./analyze_gsp_firmware.sh <firmware_bin> [output_dir]
+
+set -euo pipefail
+
+FIRMWARE_BIN="${1:-~/Git/nvidia-linux-firmware/nvidia/tu102/gsp/gsp-570.144.bin}"
+OUTPUT_DIR="${2:-/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/570-GSP}"
+PROJECT_DIR="/home/rmcore/Git/integdev_gpu_drv/open-iov/tools/ghidra/gsp-tu104-570.144"
+PROJECT_NAME="gsp-tu104-570.144"
+
+FIRMWARE_BIN=$(eval echo $FIRMWARE_BIN)
+
+echo "=== GSP Firmware Analysis Pipeline ==="
+echo "Firmware: $FIRMWARE_BIN"
+echo "Output: $OUTPUT_DIR"
+echo "Project: $PROJECT_DIR/$PROJECT_NAME"
+echo ""
+
+# Step 1: Extract .fwimage section
+echo "Step 1: Extracting .fwimage section..."
+FWIMAGE_BIN="$OUTPUT_DIR/gsp-570.144.fwimage.bin"
+objcopy -O binary -j .fwimage "$FIRMWARE_BIN" "$FWIMAGE_BIN"
+echo " Saved to $FWIMAGE_BIN ($(stat -c%s "$FWIMAGE_BIN") bytes)"
+
+# Step 2: Extract version
+echo "Step 2: Extracting version..."
+VERSION=$(readelf -x .fwversion "$FIRMWARE_BIN" | grep -A1 "Hex dump" | tail -1 | awk '{print $2$3$4$5}' | xxd -r -p)
+echo " Version: $VERSION"
+echo "$VERSION" > "$OUTPUT_DIR/gsp_version.txt"
+
+# Step 3: Extract signatures
+echo "Step 3: Extracting signatures..."
+for i in 0 1 2; do
+ objcopy -O binary -j ".fwsignature$i" "$FIRMWARE_BIN" "$OUTPUT_DIR/gsp-570.144.fwsignature$i.bin" 2>/dev/null || true
+done
+
+# Step 4: Create Ghidra project for ELF container
+echo "Step 4: Creating Ghidra project for ELF container..."
+/snap/ghidra/47/ghidra/support/analyzeHeadless "$PROJECT_DIR" "$PROJECT_NAME" \
+ -import "$FIRMWARE_BIN" \
+ -processor "RISCV:LE:64:default" \
+ -cspec "gcc" \
+ -overwrite \
+ -scriptPath "$PROJECT_DIR/scripts" \
+ -postScript "extract_fwimage.py"
+
+# Step 5: Create Ghidra project for .fwimage binary
+echo "Step 5: Creating Ghidra project for .fwimage binary..."
+FWIMAGE_PROJECT_DIR="/home/rmcore/Git/integdev_gpu_drv/open-iov/tools/ghidra/gsp-fwimage-570.144"
+FWIMAGE_PROJECT_NAME="gsp-fwimage-570.144"
+mkdir -p "$FWIMAGE_PROJECT_DIR/scripts"
+cp "$PROJECT_DIR/scripts/analyze_gsp_fwimage.py" "$FWIMAGE_PROJECT_DIR/scripts/"
+
+/snap/ghidra/47/ghidra/support/analyzeHeadless "$FWIMAGE_PROJECT_DIR" "$FWIMAGE_PROJECT_NAME" \
+ -import "$FWIMAGE_BIN" \
+ -processor "RISCV:LE:64:default" \
+ -cspec "gcc" \
+ -overwrite \
+ -scriptPath "$FWIMAGE_PROJECT_DIR/scripts" \
+ -postScript "analyze_gsp_fwimage.py"
+
+# Step 6: Also analyze bootloader and booter
+echo "Step 6: Analyzing bootloader and booter..."
+BOOTLOADER_BIN="$OUTPUT_DIR/bootloader-570.144.bin"
+BOOTER_LOAD_BIN="$OUTPUT_DIR/booter_load-570.144.bin"
+BOOTER_UNLOAD_BIN="$OUTPUT_DIR/booter_unload-570.144.bin"
+
+cp ~/Git/nvidia-linux-firmware/nvidia/tu102/gsp/bootloader-570.144.bin "$BOOTLOADER_BIN"
+cp ~/Git/nvidia-linux-firmware/nvidia/tu102/gsp/booter_load-570.144.bin "$BOOTER_LOAD_BIN"
+cp ~/Git/nvidia-linux-firmware/nvidia/tu102/gsp/booter_unload-570.144.bin "$BOOTER_UNLOAD_BIN"
+
+for name in bootloader booter_load booter_unload; do
+ bin_file="$OUTPUT_DIR/${name}-570.144.bin"
+ proj_dir="/home/rmcore/Git/integdev_gpu_drv/open-iov/tools/ghidra/gsp-${name}-570.144"
+ proj_name="gsp-${name}-570.144"
+ mkdir -p "$proj_dir/scripts"
+ cp "$PROJECT_DIR/scripts/analyze_gsp_fwimage.py" "$proj_dir/scripts/analyze_${name}.py"
+
+ # Modify script for raw binary
+ sed -i 's/program = getCurrentProgram()/program = getCurrentProgram()\n# Raw binary - set base address to 0/' "$proj_dir/scripts/analyze_${name}.py"
+
+ /snap/ghidra/47/ghidra/support/analyzeHeadless "$proj_dir" "$proj_name" \
+ -import "$bin_file" \
+ -processor "RISCV:LE:64:default" \
+ -cspec "gcc" \
+ -overwrite \
+ -scriptPath "$proj_dir/scripts" \
+ -postScript "analyze_${name}.py" 2>&1 | tail -20
+done
+
+echo ""
+echo "=== Analysis Complete ==="
+echo "Results in: $OUTPUT_DIR"
+echo ""
+echo "Key files:"
+ls -la "$OUTPUT_DIR"/*.json "$OUTPUT_DIR"/*.txt "$OUTPUT_DIR"/*.c 2>/dev/null | head -20 \ No newline at end of file
diff --git a/tools/ghidra/create_gsp_project.py b/tools/ghidra/create_gsp_project.py
new file mode 100644
index 0000000..3f505f1
--- /dev/null
+++ b/tools/ghidra/create_gsp_project.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+"""
+Create Ghidra project for GSP firmware analysis.
+Usage: python3 create_gsp_project.py <firmware_bin> <project_dir> <project_name>
+"""
+
+import sys
+import os
+import subprocess
+import shutil
+
+def create_ghidra_project(firmware_path, project_dir, project_name):
+ """Create a Ghidra project and import the GSP firmware."""
+
+ ghidra_path = "/snap/bin/ghidra"
+ analyze_headless = "/snap/ghidra/47/ghidra/support/analyzeHeadless"
+
+ if not os.path.exists(analyze_headless):
+ analyze_headless = "/opt/ghidra/support/analyzeHeadless"
+
+ if not os.path.exists(analyze_headless):
+ print("ERROR: Ghidra analyzeHeadless not found")
+ sys.exit(1)
+
+ # Create project directory
+ os.makedirs(project_dir, exist_ok=True)
+
+ # Import the firmware binary
+ cmd = [
+ analyze_headless,
+ project_dir,
+ project_name,
+ "-import", firmware_path,
+ "-processor", "RISCV:LE:64:default",
+ "-cspec", "gcc",
+ "-overwrite",
+ "-scriptPath", os.path.join(project_dir, "scripts"),
+ "-postScript", "extract_fwimage.py"
+ ]
+
+ print(f"Running: {' '.join(cmd)}")
+ result = subprocess.run(cmd, capture_output=True, text=True)
+
+ print(result.stdout)
+ if result.stderr:
+ print(result.stderr, file=sys.stderr)
+
+ return result.returncode == 0
+
+def main():
+ if len(sys.argv) < 4:
+ print("Usage: create_gsp_project.py <firmware_bin> <project_dir> <project_name>")
+ sys.exit(1)
+
+ firmware_path = sys.argv[1]
+ project_dir = sys.argv[2]
+ project_name = sys.argv[3]
+
+ if not os.path.exists(firmware_path):
+ print(f"ERROR: Firmware not found: {firmware_path}")
+ sys.exit(1)
+
+ success = create_ghidra_project(firmware_path, project_dir, project_name)
+ sys.exit(0 if success else 1)
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/tools/ghidra/diff_gsp_firmware.py b/tools/ghidra/diff_gsp_firmware.py
new file mode 100644
index 0000000..8145982
--- /dev/null
+++ b/tools/ghidra/diff_gsp_firmware.py
@@ -0,0 +1,220 @@
+#!/usr/bin/env python3
+"""
+Diff two GSP firmware versions.
+Usage: python3 diff_gsp_firmware.py <old_firmware> <new_firmware> <output_report>
+"""
+
+import sys
+import os
+import subprocess
+import json
+import hashlib
+
+def extract_fwimage(firmware_path, output_path):
+ """Extract .fwimage section from GSP firmware ELF."""
+ cmd = ["readelf", "-x", ".fwimage", firmware_path]
+ result = subprocess.run(cmd, capture_output=True, text=True)
+ # This is a hex dump, we need to parse it
+ # Better to use objcopy
+ cmd = ["objcopy", "-O", "binary", "-j", ".fwimage", firmware_path, output_path]
+ result = subprocess.run(cmd, capture_output=True)
+ return result.returncode == 0
+
+def extract_version(firmware_path):
+ """Extract version from .fwversion section."""
+ cmd = ["readelf", "-x", ".fwversion", firmware_path]
+ result = subprocess.run(cmd, capture_output=True, text=True)
+ # Parse hex dump
+ for line in result.stdout.split('\n'):
+ if '0x' in line and len(line.strip()) > 10:
+ parts = line.split()
+ if len(parts) >= 5:
+ hex_str = ''.join(parts[1:5])
+ try:
+ version = bytes.fromhex(hex_str).decode('ascii').strip('\x00')
+ return version
+ except:
+ pass
+ return "unknown"
+
+def run_ghidra_analysis(fwimage_path, project_dir, project_name):
+ """Run Ghidra analysis on fwimage."""
+ analyze_headless = "/snap/ghidra/47/ghidra/support/analyzeHeadless"
+ if not os.path.exists(analyze_headless):
+ analyze_headless = "/opt/ghidra/support/analyzeHeadless"
+
+ script_path = "/home/rmcore/Git/integdev_gpu_drv/open-iov/tools/ghidra/gsp-tu104-570.144/scripts"
+
+ cmd = [
+ analyze_headless,
+ project_dir,
+ project_name,
+ "-import", fwimage_path,
+ "-processor", "RISCV:LE:64:default",
+ "-cspec", "gcc",
+ "-overwrite",
+ "-scriptPath", script_path,
+ "-postScript", "analyze_gsp_fwimage.py"
+ ]
+
+ result = subprocess.run(cmd, capture_output=True, text=True, timeout=7200)
+ return result.returncode == 0
+
+def load_analysis_results(output_dir):
+ """Load analysis results from JSON files."""
+ results = {}
+ for fname in ["functions.json", "rpc_functions.json", "vgpu_strings.json",
+ "wpr_functions.json", "mem_functions.json", "irq_functions.json",
+ "analysis_summary.json"]:
+ path = os.path.join(output_dir, fname)
+ if os.path.exists(path):
+ with open(path, 'r') as f:
+ results[fname.replace('.json', '')] = json.load(f)
+ return results
+
+def diff_functions(old_funcs, new_funcs):
+ """Compare function lists."""
+ old_names = {f['name']: f for f in old_funcs}
+ new_names = {f['name']: f for f in new_funcs}
+
+ added = [f for name, f in new_names.items() if name not in old_names]
+ removed = [f for name, f in old_names.items() if name not in new_names]
+ modified = []
+
+ for name in set(old_names.keys()) & set(new_names.keys()):
+ if old_names[name]['size'] != new_names[name]['size'] or \
+ old_names[name]['entry'] != new_names[name]['entry']:
+ modified.append({
+ 'name': name,
+ 'old': old_names[name],
+ 'new': new_names[name]
+ })
+
+ return added, removed, modified
+
+def generate_diff_report(old_firmware, new_firmware, old_results, new_results, output_path):
+ """Generate markdown diff report."""
+ old_version = extract_version(old_firmware)
+ new_version = extract_version(new_firmware)
+
+ old_funcs = old_results.get('functions', [])
+ new_funcs = new_results.get('functions', [])
+
+ added, removed, modified = diff_functions(old_funcs, new_funcs)
+
+ old_rpc = {f['name'] for f in old_results.get('rpc_functions', [])}
+ new_rpc = {f['name'] for f in new_results.get('rpc_functions', [])}
+
+ rpc_added = new_rpc - old_rpc
+ rpc_removed = old_rpc - new_rpc
+
+ report = f"""# GSP Firmware Diff Report
+
+## Versions
+- **Old**: {old_version} ({os.path.basename(old_firmware)})
+- **New**: {new_version} ({os.path.basename(new_firmware)})
+
+## Function Changes
+- **Total Functions**: {len(old_funcs)} → {len(new_funcs)} ({len(new_funcs) - len(old_funcs):+d})
+- **Added**: {len(added)}
+- **Removed**: {len(removed)}
+- **Modified**: {len(modified)}
+
+## RPC Handler Changes
+- **Added RPC Functions**: {len(rpc_added)}
+- **Removed RPC Functions**: {len(rpc_removed)}
+
+## Added Functions
+"""
+ for f in added[:50]:
+ report += f"- `{f['name']}` at {f['entry']} (size: {f['size']})\n"
+
+ if len(added) > 50:
+ report += f"\n... and {len(added) - 50} more\n"
+
+ report += "\n## Removed Functions\n"
+ for f in removed[:50]:
+ report += f"- `{f['name']}` at {f['entry']} (size: {f['size']})\n"
+
+ if len(removed) > 50:
+ report += f"\n... and {len(removed) - 50} more\n"
+
+ report += "\n## Modified Functions\n"
+ for f in modified[:50]:
+ report += f"- `{f['name']}`: {f['old']['entry']}→{f['new']['entry']}, size {f['old']['size']}→{f['new']['size']}\n"
+
+ if len(modified) > 50:
+ report += f"\n... and {len(modified) - 50} more\n"
+
+ report += "\n## Added RPC Functions\n"
+ for name in sorted(rpc_added):
+ report += f"- `{name}`\n"
+
+ report += "\n## Removed RPC Functions\n"
+ for name in sorted(rpc_removed):
+ report += f"- `{name}`\n"
+
+ # vGPU strings comparison
+ old_strings = {s['value'] for s in old_results.get('vgpu_strings', [])}
+ new_strings = {s['value'] for s in new_results.get('vgpu_strings', [])}
+
+ report += "\n## vGPU String Changes\n"
+ report += f"- **Added**: {len(new_strings - old_strings)}\n"
+ report += f"- **Removed**: {len(old_strings - new_strings)}\n"
+
+ for s in sorted(new_strings - old_strings)[:20]:
+ report += f" + `{s}`\n"
+ for s in sorted(old_strings - new_strings)[:20]:
+ report += f" - `{s}`\n"
+
+ with open(output_path, 'w') as f:
+ f.write(report)
+
+ print(f"Diff report saved to {output_path}")
+
+def main():
+ if len(sys.argv) < 4:
+ print("Usage: diff_gsp_firmware.py <old_firmware> <new_firmware> <output_report>")
+ sys.exit(1)
+
+ old_firmware = sys.argv[1]
+ new_firmware = sys.argv[2]
+ output_report = sys.argv[3]
+
+ # Extract .fwimage sections
+ old_fwimage = "/tmp/old_fwimage.bin"
+ new_fwimage = "/tmp/new_fwimage.bin"
+
+ print("Extracting .fwimage sections...")
+ if not extract_fwimage(old_firmware, old_fwimage):
+ print("Failed to extract old .fwimage")
+ sys.exit(1)
+ if not extract_fwimage(new_firmware, new_fwimage):
+ print("Failed to extract new .fwimage")
+ sys.exit(1)
+
+ # Run Ghidra analysis on both
+ print("Analyzing old firmware...")
+ old_project_dir = "/tmp/ghidra_old"
+ if not run_ghidra_analysis(old_fwimage, old_project_dir, "gsp_old"):
+ print("Failed to analyze old firmware")
+ sys.exit(1)
+
+ print("Analyzing new firmware...")
+ new_project_dir = "/tmp/ghidra_new"
+ if not run_ghidra_analysis(new_fwimage, new_project_dir, "gsp_new"):
+ print("Failed to analyze new firmware")
+ sys.exit(1)
+
+ # Load results
+ old_results = load_analysis_results("/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/570-GSP")
+ # For new firmware, we'd need a separate output dir
+ new_results = load_analysis_results("/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/NEW-GSP")
+
+ # Generate diff report
+ generate_diff_report(old_firmware, new_firmware, old_results, new_results, output_report)
+
+ print("Done!")
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/tools/ghidra/gsp-fwimage-570.144/scripts/BasicAnalysis.java b/tools/ghidra/gsp-fwimage-570.144/scripts/BasicAnalysis.java
new file mode 100644
index 0000000..1776ea2
--- /dev/null
+++ b/tools/ghidra/gsp-fwimage-570.144/scripts/BasicAnalysis.java
@@ -0,0 +1,156 @@
+// Ghidra script to do basic disassembly analysis of GSP .fwimage binary
+// Usage: analyzeHeadless ... -postScript BasicAnalysis.java
+
+import ghidra.app.script.GhidraScript;
+import ghidra.program.model.listing.*;
+import ghidra.program.model.mem.*;
+import ghidra.program.model.symbol.*;
+import ghidra.program.model.address.*;
+import ghidra.util.task.TaskMonitor;
+import java.io.*;
+import java.util.*;
+import java.nio.file.*;
+
+public class BasicAnalysis extends GhidraScript {
+
+ @Override
+ protected void run() throws Exception {
+ Program program = getCurrentProgram();
+ Listing listing = program.getListing();
+ Memory memory = program.getMemory();
+ FunctionManager functionManager = program.getFunctionManager();
+
+ println("=== GSP Firmware .fwimage Basic Analysis ===");
+ println("Program: " + program.getName());
+ println("Architecture: " + program.getLanguage().toString());
+
+ // Create output directory
+ String outputDir = "/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/570-GSP";
+ Files.createDirectories(Paths.get(outputDir));
+
+ // 1. Check memory blocks
+ println("\n--- Memory Blocks ---");
+ List<Map<String, Object>> memBlocks = new ArrayList<>();
+ for (MemoryBlock block : memory.getBlocks()) {
+ Map<String, Object> blockInfo = new HashMap<>();
+ blockInfo.put("name", block.getName());
+ blockInfo.put("start", block.getStart().toString());
+ blockInfo.put("end", block.getEnd().toString());
+ blockInfo.put("size", block.getSize());
+ blockInfo.put("execute", block.isExecute());
+ blockInfo.put("read", block.isRead());
+ blockInfo.put("write", block.isWrite());
+ memBlocks.add(blockInfo);
+ println(" " + block.getName() + ": " + block.getStart() + " - " + block.getEnd() +
+ " (" + block.getSize() + " bytes) r=" + block.isRead() + " w=" + block.isWrite() + " x=" + block.isExecute());
+ }
+ writeJson(outputDir + "/memory_blocks.json", memBlocks);
+
+ // 2. Find all functions
+ println("\n--- Finding Functions ---");
+ List<Map<String, Object>> functions = new ArrayList<>();
+ FunctionIterator funcIter = functionManager.getFunctions(true);
+ int count = 0;
+ while (funcIter.hasNext()) {
+ Function func = funcIter.next();
+ Map<String, Object> funcInfo = new HashMap<>();
+ funcInfo.put("name", func.getName());
+ funcInfo.put("entry", func.getEntryPoint().toString());
+ funcInfo.put("size", func.getBody().getNumAddresses());
+ functions.add(funcInfo);
+ count++;
+ if (count % 1000 == 0) {
+ println(" Found " + count + " functions...");
+ }
+ }
+ println("Total functions: " + functions.size());
+ writeJson(outputDir + "/functions.json", functions);
+
+ // 3. Find strings
+ println("\n--- Finding Strings ---");
+ List<Map<String, String>> strings = new ArrayList<>();
+ DataIterator dataIter = listing.getDefinedData(true);
+ while (dataIter.hasNext()) {
+ Data data = dataIter.next();
+ if (data.getDataType().getName().equals("string")) {
+ Object value = data.getValue();
+ if (value != null && value.toString().length() > 4) {
+ Map<String, String> strInfo = new HashMap<>();
+ strInfo.put("address", data.getAddress().toString());
+ strInfo.put("value", value.toString());
+ strings.add(strInfo);
+ }
+ }
+ }
+ println("Found " + strings.size() + " strings");
+
+ // Filter for interesting strings
+ String[] interestingKeywords = {"vgpu", "vmiop", "rpc", "hal", "bar", "migrate", "init", "boot", "kgsp", "wpr", "firmware", "version", "error", "fail", "assert", "panic", "nvidia", "rmapi", "gsp", "falcon", "mailbox", "interrupt", "dma", "iommu", "page", "mmu", "pde", "pte"};
+ List<Map<String, String>> interestingStrings = new ArrayList<>();
+ for (Map<String, String> s : strings) {
+ String val = s.get("value").toLowerCase();
+ for (String kw : interestingKeywords) {
+ if (val.contains(kw)) {
+ interestingStrings.add(s);
+ break;
+ }
+ }
+ }
+ println("Interesting strings: " + interestingStrings.size());
+ writeJson(outputDir + "/interesting_strings.json", interestingStrings);
+
+ // 4. Find entry point
+ println("\n--- Entry Point Analysis ---");
+ Address entryAddr = program.getMinAddress();
+ println("Program entry (min address): " + entryAddr);
+ Function funcAtZero = functionManager.getFunctionAt(entryAddr);
+ if (funcAtZero != null) {
+ println("Function at entry: " + funcAtZero.getName());
+ } else {
+ println("No function at entry point - creating one...");
+ Function func = functionManager.createFunction("entry_point", entryAddr, null, null, monitor);
+ if (func != null) {
+ println("Created function: " + func.getName());
+ }
+ }
+
+ println("\n--- Analysis Complete ---");
+ println("Results saved to " + outputDir);
+ }
+
+ private void writeJson(String path, Object data) throws IOException {
+ StringBuilder json = new StringBuilder();
+ json.append("[\n");
+ if (data instanceof List) {
+ List<?> list = (List<?>) data;
+ for (int i = 0; i < list.size(); i++) {
+ Object item = list.get(i);
+ if (item instanceof Map) {
+ Map<?, ?> map = (Map<?, ?>) item;
+ json.append(" {");
+ int j = 0;
+ for (Map.Entry<?, ?> entry : map.entrySet()) {
+ json.append("\"").append(entry.getKey()).append("\": ");
+ Object val = entry.getValue();
+ if (val instanceof String) {
+ json.append("\"").append(escapeJson(val.toString())).append("\"");
+ } else {
+ json.append(val);
+ }
+ if (j < map.size() - 1) json.append(", ");
+ j++;
+ }
+ json.append("}");
+ }
+ if (i < list.size() - 1) json.append(",");
+ json.append("\n");
+ }
+ }
+ json.append("]");
+ Files.writeString(Paths.get(path), json.toString());
+ }
+
+ private String escapeJson(String s) {
+ return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
+ }
+} \ No newline at end of file
diff --git a/tools/ghidra/gsp-fwimage-570.144/scripts/DecompileFunctions.java b/tools/ghidra/gsp-fwimage-570.144/scripts/DecompileFunctions.java
new file mode 100644
index 0000000..da522cd
--- /dev/null
+++ b/tools/ghidra/gsp-fwimage-570.144/scripts/DecompileFunctions.java
@@ -0,0 +1,88 @@
+import ghidra.app.script.GhidraScript;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.Function;
+import ghidra.program.model.listing.FunctionManager;
+import ghidra.app.decompiler.DecompInterface;
+import ghidra.app.decompiler.DecompileResults;
+import ghidra.util.task.TaskMonitor;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+public class DecompileFunctions extends GhidraScript {
+ private static final String OUTPUT_DIR = "/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/570-GSP/decompiled/";
+
+ @Override
+ protected void run() throws Exception {
+ File outDir = new File(OUTPUT_DIR);
+ if (!outDir.exists()) {
+ outDir.mkdirs();
+ }
+
+ String[] args = getScriptArgs();
+ if (args.length == 0) {
+ println("No addresses provided. Usage: <addr1>,<addr2>,...");
+ return;
+ }
+
+ Set<Address> targetAddresses = new HashSet<>();
+ for (String arg : args) {
+ String[] addrs = arg.split(",");
+ for (String addrStr : addrs) {
+ addrStr = addrStr.trim();
+ if (addrStr.startsWith("0x")) {
+ addrStr = addrStr.substring(2);
+ }
+ Address addr = toAddr(addrStr);
+ if (addr != null) {
+ targetAddresses.add(addr);
+ println("Target: " + addr);
+ }
+ }
+ }
+
+ FunctionManager fm = currentProgram.getFunctionManager();
+ DecompInterface decompiler = new DecompInterface();
+ decompiler.openProgram(currentProgram);
+
+ for (Address addr : targetAddresses) {
+ Function func = fm.getFunctionAt(addr);
+ if (func == null) {
+ println("No function at " + addr + ", creating...");
+ func = createFunction(addr, null);
+ }
+ if (func != null) {
+ decompileAndSave(func, decompiler);
+ } else {
+ println("Failed to create function at " + addr);
+ }
+ }
+
+ decompiler.dispose();
+ }
+
+ private void decompileAndSave(Function func, DecompInterface decompiler) throws Exception {
+ String name = func.getName();
+ Address entry = func.getEntryPoint();
+ String safeName = name.replaceAll("[^a-zA-Z0-9_]", "_");
+ File outFile = new File(OUTPUT_DIR, safeName + "_" + entry.toString().replace(":", "_") + ".c");
+
+ DecompileResults results = decompiler.decompileFunction(func, 60, TaskMonitor.DUMMY);
+ if (results.decompileCompleted()) {
+ String code = results.getDecompiledFunction().getC();
+ try (PrintWriter pw = new PrintWriter(new FileWriter(outFile))) {
+ pw.println("// Function: " + name);
+ pw.println("// Address: " + entry);
+ pw.println("// Size: " + func.getBody().getNumAddresses() + " bytes");
+ pw.println();
+ pw.print(code);
+ }
+ println("Decompiled: " + name + " @ " + entry + " -> " + outFile.getName());
+ } else {
+ println("Decompilation failed for " + name + " @ " + entry + ": " + results.getErrorMessage());
+ }
+ }
+} \ No newline at end of file
diff --git a/tools/ghidra/gsp-fwimage-570.144/scripts/ExtractFunctions.java b/tools/ghidra/gsp-fwimage-570.144/scripts/ExtractFunctions.java
new file mode 100644
index 0000000..2296a42
--- /dev/null
+++ b/tools/ghidra/gsp-fwimage-570.144/scripts/ExtractFunctions.java
@@ -0,0 +1,126 @@
+import ghidra.app.script.GhidraScript;
+import ghidra.program.model.listing.FunctionManager;
+import ghidra.program.model.listing.Function;
+import ghidra.program.model.listing.FunctionIterator;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.Program;
+import ghidra.program.model.mem.Memory;
+import ghidra.program.model.mem.MemoryBlock;
+import ghidra.util.task.TaskMonitor;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExtractFunctions extends GhidraScript {
+
+ @Override
+ protected void run() throws Exception {
+ Program program = currentProgram;
+ FunctionManager functionManager = program.getFunctionManager();
+ Memory memory = program.getMemory();
+
+ String outputDir = "/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/570-GSP";
+
+ // 1. Extract memory blocks
+ List<MemoryBlockInfo> memBlocks = new ArrayList<>();
+ for (MemoryBlock block : memory.getBlocks()) {
+ memBlocks.add(new MemoryBlockInfo(
+ block.getName(),
+ block.getStart().toString(),
+ block.getEnd().toString(),
+ block.getSize(),
+ block.isExecute(),
+ block.isRead(),
+ block.isWrite()
+ ));
+ }
+ writeJson(outputDir + "/memory_blocks.json", memBlocks);
+
+ // 2. Extract all functions (analysis must have run first)
+ List<FunctionInfo> functions = new ArrayList<>();
+ FunctionIterator funcIter = functionManager.getFunctions(true);
+ while (funcIter.hasNext()) {
+ Function func = funcIter.next();
+ functions.add(new FunctionInfo(
+ func.getName(),
+ func.getEntryPoint().toString(),
+ func.getBody().getNumAddresses()
+ ));
+ }
+ writeJson(outputDir + "/functions.json", functions);
+
+ // 3. Extract interesting strings
+ String[] keywords = {"vgpu", "vmiop", "rpc", "hal", "bar", "migrate", "init", "boot", "kgsp", "wpr", "firmware", "version", "error", "fail", "assert", "panic", "nvidia", "rmapi", "gsp", "falcon", "mailbox", "interrupt", "dma", "iommu", "page", "mmu", "pde", "pte"};
+ List<StringInfo> strings = new ArrayList<>();
+ var listing = program.getListing();
+ var dataIter = listing.getDefinedData(true);
+ while (dataIter.hasNext()) {
+ var data = dataIter.next();
+ if (data.getDataType().getName().equals("string")) {
+ String value = data.getValue().toString();
+ if (value.length() > 4) {
+ String lower = value.toLowerCase();
+ for (String kw : keywords) {
+ if (lower.contains(kw)) {
+ strings.add(new StringInfo(data.getAddress().toString(), value));
+ break;
+ }
+ }
+ }
+ }
+ }
+ writeJson(outputDir + "/interesting_strings.json", strings);
+
+ println("Extracted " + functions.size() + " functions, " + memBlocks.size() + " memory blocks, " + strings.size() + " interesting strings");
+ }
+
+ private void writeJson(String path, List<?> list) throws IOException {
+ try (FileWriter fw = new FileWriter(path)) {
+ fw.write("[\n");
+ for (int i = 0; i < list.size(); i++) {
+ fw.write(" " + toJson(list.get(i)));
+ if (i < list.size() - 1) fw.write(",");
+ fw.write("\n");
+ }
+ fw.write("]\n");
+ }
+ }
+
+ private String toJson(Object obj) {
+ if (obj instanceof MemoryBlockInfo) {
+ MemoryBlockInfo m = (MemoryBlockInfo) obj;
+ return String.format("{\"name\":\"%s\",\"start\":\"%s\",\"end\":\"%s\",\"size\":%d,\"execute\":%b,\"read\":%b,\"write\":%b}",
+ m.name, m.start, m.end, m.size, m.execute, m.read, m.write);
+ } else if (obj instanceof FunctionInfo) {
+ FunctionInfo f = (FunctionInfo) obj;
+ return String.format("{\"name\":\"%s\",\"entry\":\"%s\",\"size\":%d}",
+ f.name, f.entry, f.size);
+ } else if (obj instanceof StringInfo) {
+ StringInfo s = (StringInfo) obj;
+ return String.format("{\"address\":\"%s\",\"value\":\"%s\"}",
+ s.address, s.value.replace("\\", "\\\\").replace("\"", "\\\""));
+ }
+ return "{}";
+ }
+
+ static class MemoryBlockInfo {
+ String name, start, end;
+ long size;
+ boolean execute, read, write;
+ MemoryBlockInfo(String n, String s, String e, long sz, boolean ex, boolean rd, boolean wr) {
+ name = n; start = s; end = e; size = sz; execute = ex; read = rd; write = wr;
+ }
+ }
+
+ static class FunctionInfo {
+ String name, entry;
+ long size;
+ FunctionInfo(String n, String e, long sz) { name = n; entry = e; size = sz; }
+ }
+
+ static class StringInfo {
+ String address, value;
+ StringInfo(String a, String v) { address = a; value = v; }
+ }
+}
diff --git a/tools/ghidra/gsp-fwimage-570.144/scripts/basic_analysis.py b/tools/ghidra/gsp-fwimage-570.144/scripts/basic_analysis.py
new file mode 100644
index 0000000..4992106
--- /dev/null
+++ b/tools/ghidra/gsp-fwimage-570.144/scripts/basic_analysis.py
@@ -0,0 +1,108 @@
+# Ghidra script to do basic disassembly analysis of GSP .fwimage binary
+# Usage: analyzeHeadless ... -postScript basic_analysis.py
+
+import sys
+import os
+import json
+
+# Get the current program
+program = getCurrentProgram()
+listing = program.getListing()
+memory = program.getMemory()
+function_manager = program.getFunctionManager()
+
+print("=== GSP Firmware .fwimage Basic Analysis ===")
+print(f"Program: {program.getName()}")
+print(f"Architecture: {program.getLanguage().toString()}")
+
+# Create output directory
+output_dir = "/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/570-GSP"
+os.makedirs(output_dir, exist_ok=True)
+
+# 1. Check memory blocks
+print("\n--- Memory Blocks ---")
+mem_blocks = []
+for block in memory.getBlocks():
+ mem_blocks.append({
+ "name": block.getName(),
+ "start": str(block.getStart()),
+ "end": str(block.getEnd()),
+ "size": block.getSize(),
+ "execute": block.isExecute(),
+ "read": block.isRead(),
+ "write": block.isWrite()
+ })
+ print(f" {block.getName()}: {block.getStart()} - {block.getEnd()} ({block.getSize()} bytes) r={block.isRead()} w={block.isWrite()} x={block.isExecute()}")
+
+with open(os.path.join(output_dir, "memory_blocks.json"), "w") as f:
+ json.dump(mem_blocks, f, indent=2)
+
+# 2. Find all functions (but don't decompile yet)
+print("\n--- Finding Functions ---")
+functions = []
+func_iter = function_manager.getFunctions(True)
+count = 0
+while func_iter.hasNext():
+ func = func_iter.next()
+ functions.append({
+ "name": func.getName(),
+ "entry": str(func.getEntryPoint()),
+ "size": func.getBody().getNumAddresses()
+ })
+ count += 1
+ if count % 1000 == 0:
+ print(f" Found {count} functions...")
+
+print(f"Total functions: {len(functions)}")
+
+with open(os.path.join(output_dir, "functions.json"), "w") as f:
+ json.dump(functions, f, indent=2)
+
+# 3. Find strings
+print("\n--- Finding Strings ---")
+strings = []
+string_iter = listing.getDefinedData(True)
+while string_iter.hasNext():
+ data = string_iter.next()
+ if data.getDataType().getName() == "string":
+ value = data.getValue()
+ if value and len(str(value)) > 4:
+ strings.append({
+ "address": str(data.getAddress()),
+ "value": str(value)
+ })
+
+print(f"Found {len(strings)} strings")
+
+# Filter for interesting strings
+interesting_keywords = ["vgpu", "vmiop", "rpc", "hal", "bar", "migrate", "init", "boot", "kgsp", "wpr", "firmware", "version", "error", "fail", "assert", "panic", "nvidia", "rmapi", "gsp", "falcon", "mailbox", "interrupt", "dma", "iommu", "page", "mmu", "pde", "pte"]
+interesting_strings = [s for s in strings if any(kw in s['value'].lower() for kw in interesting_keywords)]
+print(f"Interesting strings: {len(interesting_strings)}")
+
+with open(os.path.join(output_dir, "interesting_strings.json"), "w") as f:
+ json.dump(interesting_strings, f, indent=2)
+
+# 4. Find entry point (offset 0)
+print("\n--- Entry Point Analysis ---")
+entry_addr = program.getMinAddress()
+print(f"Program entry (min address): {entry_addr}")
+
+# Check what's at address 0
+func_at_zero = function_manager.getFunctionAt(entry_addr)
+if func_at_zero:
+ print(f"Function at entry: {func_at_zero.getName()}")
+else:
+ print("No function at entry point - creating one...")
+ # Create function at entry point
+ func = function_manager.createFunction("entry_point", entry_addr, None, None)
+ if func:
+ print(f"Created function: {func.getName()}")
+
+# 5. Look for RISC-V standard function prologues
+print("\n--- Looking for Function Prologues ---")
+# RISC-V typical prologue: addi sp, sp, -X; sd ra, X-8(sp); sd s0, X-16(sp); addi s0, sp, X
+# Let's search for common patterns
+
+# 6. Find cross-references to interesting addresses
+print("\n--- Analysis Complete ---")
+print(f"Results saved to {output_dir}") \ No newline at end of file
diff --git a/tools/ghidra/gsp-tu104-570.144/scripts/DecompileFunctions.java b/tools/ghidra/gsp-tu104-570.144/scripts/DecompileFunctions.java
new file mode 100644
index 0000000..e1d78c3
--- /dev/null
+++ b/tools/ghidra/gsp-tu104-570.144/scripts/DecompileFunctions.java
@@ -0,0 +1,143 @@
+import ghidra.app.script.GhidraScript;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.Function;
+import ghidra.program.model.listing.FunctionManager;
+import ghidra.program.model.listing.Instruction;
+import ghidra.program.model.listing.Program;
+import ghidra.program.model.mem.Memory;
+import ghidra.app.decompiler.DecompInterface;
+import ghidra.app.decompiler.DecompileResults;
+import ghidra.util.task.TaskMonitor;
+import java.io.*;
+
+public class DecompileFunctions extends GhidraScript {
+
+ private DecompInterface decompiler;
+
+ @Override
+ protected void run() throws Exception {
+ decompiler = new DecompInterface();
+ decompiler.openProgram(currentProgram);
+
+ String[] args = getScriptArgs();
+ if (args.length == 0) {
+ println("Usage: DecompileFunctions.java <comma-separated-addresses>");
+ return;
+ }
+
+ String[] addresses = args[0].split(",");
+
+ println("=== Targeted Decompilation ===");
+ for (String addrStr : addresses) {
+ addrStr = addrStr.trim();
+ if (addrStr.isEmpty()) continue;
+
+ long addrVal;
+ try {
+ addrVal = Long.parseUnsignedLong(addrStr.startsWith("0x") ? addrStr.substring(2) : addrStr, 16);
+ } catch (NumberFormatException e) {
+ println("Invalid address: " + addrStr);
+ continue;
+ }
+
+ Address addr = currentProgram.getAddressFactory().getAddress("0x" + Long.toHexString(addrVal));
+ if (addr == null) {
+ println("Invalid address: " + addrStr);
+ continue;
+ }
+
+ decompileFunction(addr);
+ }
+
+ println("\n=== Decompilation Complete ===");
+ }
+
+ private void decompileFunction(Address entryAddr) throws Exception {
+ FunctionManager fm = currentProgram.getFunctionManager();
+ Memory mem = currentProgram.getMemory();
+
+ // Manually disassemble from entry point by creating instructions
+ Address addr = entryAddr;
+ int maxBytes = 2000;
+ int bytes = 0;
+
+ while (bytes < maxBytes && !monitor.isCancelled()) {
+ Instruction instr = currentProgram.getListing().getInstructionAt(addr);
+ if (instr != null) {
+ addr = instr.getMaxAddress().next();
+ bytes += instr.getLength();
+ continue;
+ }
+
+ // Try to create instruction from bytes
+ try {
+ byte[] buf = new byte[4];
+ int read = mem.getBytes(addr, buf);
+ if (read <= 0) break;
+
+ // Create instruction prototype and try to disassemble
+ instr = currentProgram.getListing().createInstruction(addr,
+ currentProgram.getLanguage().getInstructionPrototype(buf),
+ new ghidra.program.model.mem.ByteMemBuffer(buf, 0, read),
+ currentProgram.getProgramContext(), 0);
+
+ if (instr != null) {
+ addr = instr.getMaxAddress().next();
+ bytes += instr.getLength();
+ } else {
+ addr = addr.next().next();
+ bytes += 2;
+ }
+ } catch (Exception e) {
+ addr = addr.next().next();
+ bytes += 2;
+ }
+ }
+ println(" Disassembled " + bytes + " bytes from " + entryAddr);
+
+ // Get or create function
+ Function func = fm.getFunctionAt(entryAddr);
+ if (func == null) {
+ func = fm.createFunction("FUNC_" + Long.toHexString(entryAddr.getOffset()).toUpperCase(),
+ entryAddr, null, ghidra.program.model.symbol.SourceType.ANALYSIS);
+ if (func == null) {
+ println("Failed to create function at " + entryAddr);
+ return;
+ }
+ println("Created function: " + func.getName() + " @ " + func.getEntryPoint());
+ } else {
+ println("Existing function: " + func.getName() + " @ " + func.getEntryPoint());
+ }
+
+ // Decompile
+ println("\n--- Decompiling " + func.getName() + " @ " + func.getEntryPoint() + " ---");
+ DecompileResults results = decompiler.decompileFunction(func, 120, monitor);
+
+ if (results.decompileCompleted()) {
+ String cCode = results.getDecompiledFunction().getC();
+
+ // Save to file
+ String filename = "/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/570-GSP/decompiled_"
+ + func.getName() + ".c";
+ try (PrintWriter pw = new PrintWriter(new FileWriter(filename))) {
+ pw.println("// Function: " + func.getName());
+ pw.println("// Address: " + func.getEntryPoint());
+ pw.println("// Stack frame: " + func.getStackFrame().getFrameSize() + " bytes");
+ pw.println();
+ pw.print(cCode);
+ }
+ println(" Saved to: " + filename);
+
+ // Print first 100 lines
+ String[] lines = cCode.split("\n");
+ for (int i = 0; i < Math.min(100, lines.length); i++) {
+ println(" " + lines[i]);
+ }
+ if (lines.length > 100) {
+ println(" ... (" + (lines.length - 100) + " more lines)");
+ }
+ } else {
+ println(" Decompilation failed: " + results.getErrorMessage());
+ }
+ }
+}
diff --git a/tools/ghidra/gsp-tu104-570.144/scripts/analyze_gsp_fwimage.py b/tools/ghidra/gsp-tu104-570.144/scripts/analyze_gsp_fwimage.py
new file mode 100644
index 0000000..4a6fb56
--- /dev/null
+++ b/tools/ghidra/gsp-tu104-570.144/scripts/analyze_gsp_fwimage.py
@@ -0,0 +1,207 @@
+# Ghidra script to analyze GSP .fwimage binary
+# Usage: analyzeHeadless ... -postScript analyze_gsp_fwimage.py
+
+import sys
+import os
+import json
+
+# Get the current program
+program = getCurrentProgram()
+listing = program.getListing()
+memory = program.getMemory()
+function_manager = program.getFunctionManager()
+
+print("=== GSP Firmware .fwimage Analysis ===")
+print(f"Program: {program.getName()}")
+print(f"Architecture: {program.getLanguage().toString()}")
+
+# Create output directory
+output_dir = "/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/570-GSP"
+os.makedirs(output_dir, exist_ok=True)
+
+# 1. Find all functions
+print("\n--- Finding Functions ---")
+functions = []
+func_iter = function_manager.getFunctions(True)
+while func_iter.hasNext():
+ func = func_iter.next()
+ functions.append({
+ "name": func.getName(),
+ "entry": str(func.getEntryPoint()),
+ "size": func.getBody().getNumAddresses(),
+ "signature": func.getSignature().toString() if func.getSignature() else ""
+ })
+
+print(f"Found {len(functions)} functions")
+
+# Save function list
+with open(os.path.join(output_dir, "functions.json"), "w") as f:
+ json.dump(functions, f, indent=2)
+
+# 2. Find RPC-related functions (vRPC/pRPC handlers)
+print("\n--- Finding RPC Handlers ---")
+rpc_keywords = [
+ "rpc", "Rpc", "RPC",
+ "vgpu", "Vgpu", "VGPU",
+ "vmiop", "Vmiop", "VMIOP",
+ "hal", "Hal", "HAL",
+ "bar", "Bar", "BAR",
+ "migrate", "Migrate", "MIGRATE",
+ "init", "Init", "INIT",
+ "boot", "Boot", "BOOT",
+ "kgsp", "Kgsp", "KGSP"
+]
+
+rpc_functions = []
+for func in functions:
+ name_lower = func["name"].lower()
+ for kw in rpc_keywords:
+ if kw.lower() in name_lower:
+ rpc_functions.append(func)
+ break
+
+print(f"Found {len(rpc_functions)} potential RPC-related functions")
+with open(os.path.join(output_dir, "rpc_functions.json"), "w") as f:
+ json.dump(rpc_functions, f, indent=2)
+
+# 3. Find strings related to vGPU initialization
+print("\n--- Finding vGPU-related Strings ---")
+vgpu_strings = []
+string_iter = listing.getDefinedData(True)
+while string_iter.hasNext():
+ data = string_iter.next()
+ if data.getDataType().getName() == "string":
+ value = data.getValue()
+ if value:
+ val_str = str(value).lower()
+ if any(kw in val_str for kw in ["vgpu", "vmiop", "rpc", "hal", "bar", "migrate", "init", "boot", "kgsp", "wpr", "firmware", "version"]):
+ vgpu_strings.append({
+ "address": str(data.getAddress()),
+ "value": str(value)
+ })
+
+print(f"Found {len(vgpu_strings)} vGPU-related strings")
+with open(os.path.join(output_dir, "vgpu_strings.json"), "w") as f:
+ json.dump(vgpu_strings, f, indent=2)
+
+# 4. Find entry points and initialization functions
+print("\n--- Finding Entry Points ---")
+entry_points = []
+# Look for common entry point names
+entry_names = [
+ "kgspInitRm_IMPL", "kgspInitRm", "kgspBootGspRm", "kgspBootGspRm_IMPL",
+ "gspBoot", "gspInit", "gspMain",
+ "nv_vgpu_vfio_get_ops", "nv_vgpu_vfio_set_ops",
+ "vgpu_init", "vgpu_init_IMPL",
+ "vmiop_init", "vmiop_init_IMPL",
+ "hal_init", "hal_init_IMPL"
+]
+
+for name in entry_names:
+ func = function_manager.getFunction(name)
+ if func:
+ entry_points.append({
+ "name": name,
+ "entry": str(func.getEntryPoint()),
+ "size": func.getBody().getNumAddresses()
+ })
+ print(f" Found: {name} at {func.getEntryPoint()}")
+
+# Also check for functions called from reset vector / entry
+# Look at the first few instructions
+entry_addr = program.getMinAddress()
+print(f"\nProgram entry address: {entry_addr}")
+
+# 5. Find WPR (Write Protected Region) related code
+print("\n--- Finding WPR-related Code ---")
+wpr_functions = []
+for func in functions:
+ name_lower = func["name"].lower()
+ if "wpr" in name_lower or "write_protect" in name_lower or "protect" in name_lower:
+ wpr_functions.append(func)
+
+print(f"Found {len(wpr_functions)} WPR-related functions")
+with open(os.path.join(output_dir, "wpr_functions.json"), "w") as f:
+ json.dump(wpr_functions, f, indent=2)
+
+# 6. Find memory management functions
+print("\n--- Finding Memory Management Functions ---")
+mem_keywords = ["alloc", "free", "map", "unmap", "pin", "unpin", "dma", "iommu", "mmio", "bar"]
+mem_functions = []
+for func in functions:
+ name_lower = func["name"].lower()
+ for kw in mem_keywords:
+ if kw in name_lower:
+ mem_functions.append(func)
+ break
+
+print(f"Found {len(mem_functions)} memory management functions")
+with open(os.path.join(output_dir, "mem_functions.json"), "w") as f:
+ json.dump(mem_functions, f, indent=2)
+
+# 7. Find interrupt/MSI-X related functions
+print("\n--- Finding Interrupt/MSI-X Functions ---")
+irq_keywords = ["irq", "interrupt", "msi", "msix", "eventfd", "doorbell"]
+irq_functions = []
+for func in functions:
+ name_lower = func["name"].lower()
+ for kw in irq_keywords:
+ if kw in name_lower:
+ irq_functions.append(func)
+ break
+
+print(f"Found {len(irq_functions)} interrupt-related functions")
+with open(os.path.join(output_dir, "irq_functions.json"), "w") as f:
+ json.dump(irq_functions, f, indent=2)
+
+# 8. Generate summary report
+print("\n--- Generating Summary Report ---")
+report = {
+ "firmware": "gsp-570.144",
+ "architecture": program.getLanguage().toString(),
+ "total_functions": len(functions),
+ "rpc_functions": len(rpc_functions),
+ "vgpu_strings": len(vgpu_strings),
+ "entry_points": entry_points,
+ "wpr_functions": len(wpr_functions),
+ "mem_functions": len(mem_functions),
+ "irq_functions": len(irq_functions)
+}
+
+with open(os.path.join(output_dir, "analysis_summary.json"), "w") as f:
+ json.dump(report, f, indent=2)
+
+# Print summary
+print(json.dumps(report, indent=2))
+
+# 9. Decompile key functions and save
+print("\n--- Decompiling Key Functions ---")
+from ghidra.app.decompiler import DecompInterface
+from ghidra.util.task import ConsoleTaskMonitor
+
+decompiler = DecompInterface()
+decompiler.openProgram(program)
+monitor = ConsoleTaskMonitor()
+
+key_functions = entry_points + rpc_functions[:20] + wpr_functions + mem_functions[:10] + irq_functions[:10]
+decompiled = {}
+
+for func_info in key_functions:
+ func = function_manager.getFunctionAt(func_info["entry"])
+ if func:
+ result = decompiler.decompileFunction(func, 60, monitor)
+ if result.decompileCompleted():
+ decompiled[func_info["name"]] = result.getDecompiledFunction().getC()
+ print(f" Decompiled: {func_info['name']}")
+ else:
+ print(f" Failed to decompile: {func_info['name']}")
+
+# Save decompiled code
+with open(os.path.join(output_dir, "decompiled_key_functions.c"), "w") as f:
+ for name, code in decompiled.items():
+ f.write(f"\n// ===== {name} =====\n")
+ f.write(code)
+ f.write("\n")
+
+print(f"\nDecompiled {len(decompiled)} key functions")
+print("Analysis complete!") \ No newline at end of file
diff --git a/tools/ghidra/gsp-tu104-570.144/scripts/basic_analysis.py b/tools/ghidra/gsp-tu104-570.144/scripts/basic_analysis.py
new file mode 100644
index 0000000..4992106
--- /dev/null
+++ b/tools/ghidra/gsp-tu104-570.144/scripts/basic_analysis.py
@@ -0,0 +1,108 @@
+# Ghidra script to do basic disassembly analysis of GSP .fwimage binary
+# Usage: analyzeHeadless ... -postScript basic_analysis.py
+
+import sys
+import os
+import json
+
+# Get the current program
+program = getCurrentProgram()
+listing = program.getListing()
+memory = program.getMemory()
+function_manager = program.getFunctionManager()
+
+print("=== GSP Firmware .fwimage Basic Analysis ===")
+print(f"Program: {program.getName()}")
+print(f"Architecture: {program.getLanguage().toString()}")
+
+# Create output directory
+output_dir = "/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/570-GSP"
+os.makedirs(output_dir, exist_ok=True)
+
+# 1. Check memory blocks
+print("\n--- Memory Blocks ---")
+mem_blocks = []
+for block in memory.getBlocks():
+ mem_blocks.append({
+ "name": block.getName(),
+ "start": str(block.getStart()),
+ "end": str(block.getEnd()),
+ "size": block.getSize(),
+ "execute": block.isExecute(),
+ "read": block.isRead(),
+ "write": block.isWrite()
+ })
+ print(f" {block.getName()}: {block.getStart()} - {block.getEnd()} ({block.getSize()} bytes) r={block.isRead()} w={block.isWrite()} x={block.isExecute()}")
+
+with open(os.path.join(output_dir, "memory_blocks.json"), "w") as f:
+ json.dump(mem_blocks, f, indent=2)
+
+# 2. Find all functions (but don't decompile yet)
+print("\n--- Finding Functions ---")
+functions = []
+func_iter = function_manager.getFunctions(True)
+count = 0
+while func_iter.hasNext():
+ func = func_iter.next()
+ functions.append({
+ "name": func.getName(),
+ "entry": str(func.getEntryPoint()),
+ "size": func.getBody().getNumAddresses()
+ })
+ count += 1
+ if count % 1000 == 0:
+ print(f" Found {count} functions...")
+
+print(f"Total functions: {len(functions)}")
+
+with open(os.path.join(output_dir, "functions.json"), "w") as f:
+ json.dump(functions, f, indent=2)
+
+# 3. Find strings
+print("\n--- Finding Strings ---")
+strings = []
+string_iter = listing.getDefinedData(True)
+while string_iter.hasNext():
+ data = string_iter.next()
+ if data.getDataType().getName() == "string":
+ value = data.getValue()
+ if value and len(str(value)) > 4:
+ strings.append({
+ "address": str(data.getAddress()),
+ "value": str(value)
+ })
+
+print(f"Found {len(strings)} strings")
+
+# Filter for interesting strings
+interesting_keywords = ["vgpu", "vmiop", "rpc", "hal", "bar", "migrate", "init", "boot", "kgsp", "wpr", "firmware", "version", "error", "fail", "assert", "panic", "nvidia", "rmapi", "gsp", "falcon", "mailbox", "interrupt", "dma", "iommu", "page", "mmu", "pde", "pte"]
+interesting_strings = [s for s in strings if any(kw in s['value'].lower() for kw in interesting_keywords)]
+print(f"Interesting strings: {len(interesting_strings)}")
+
+with open(os.path.join(output_dir, "interesting_strings.json"), "w") as f:
+ json.dump(interesting_strings, f, indent=2)
+
+# 4. Find entry point (offset 0)
+print("\n--- Entry Point Analysis ---")
+entry_addr = program.getMinAddress()
+print(f"Program entry (min address): {entry_addr}")
+
+# Check what's at address 0
+func_at_zero = function_manager.getFunctionAt(entry_addr)
+if func_at_zero:
+ print(f"Function at entry: {func_at_zero.getName()}")
+else:
+ print("No function at entry point - creating one...")
+ # Create function at entry point
+ func = function_manager.createFunction("entry_point", entry_addr, None, None)
+ if func:
+ print(f"Created function: {func.getName()}")
+
+# 5. Look for RISC-V standard function prologues
+print("\n--- Looking for Function Prologues ---")
+# RISC-V typical prologue: addi sp, sp, -X; sd ra, X-8(sp); sd s0, X-16(sp); addi s0, sp, X
+# Let's search for common patterns
+
+# 6. Find cross-references to interesting addresses
+print("\n--- Analysis Complete ---")
+print(f"Results saved to {output_dir}") \ No newline at end of file
diff --git a/tools/ghidra/gsp-tu104-570.144/scripts/extract_fwimage.py b/tools/ghidra/gsp-tu104-570.144/scripts/extract_fwimage.py
new file mode 100644
index 0000000..d8b0bfd
--- /dev/null
+++ b/tools/ghidra/gsp-tu104-570.144/scripts/extract_fwimage.py
@@ -0,0 +1,56 @@
+# Ghidra script to extract .fwimage section from GSP firmware ELF
+# Usage: analyzeHeadless ... -postScript extract_fwimage.py
+
+import sys
+import os
+
+# Get the current program
+program = getCurrentProgram()
+
+# Get the .fwimage section
+fwimage_section = program.getSection(".fwimage")
+if not fwimage_section:
+ print("No .fwimage section found")
+ sys.exit(1)
+
+print(f"Found .fwimage section: {fwimage_section.getStart()} - {fwimage_section.getEnd()}")
+print(f"Size: {fwimage_section.getLength()} bytes")
+
+# Get the data from the section
+data = getBytes(fwimage_section.getStart(), fwimage_section.getLength())
+
+# Save to file
+output_dir = "/home/rmcore/Git/integdev_gpu_drv/open-iov/firmware/570-GSP"
+os.makedirs(output_dir, exist_ok=True)
+fwimage_path = os.path.join(output_dir, "gsp-570.144.fwimage.bin")
+
+with open(fwimage_path, "wb") as f:
+ f.write(data)
+
+print(f"Saved .fwimage to {fwimage_path}")
+
+# Also extract .fwversion
+fwversion_section = program.getSection(".fwversion")
+if fwversion_section:
+ version_data = getBytes(fwversion_section.getStart(), fwversion_section.getLength())
+ version_str = version_data.decode('ascii').strip('\x00')
+ print(f"GSP Firmware Version: {version_str}")
+
+ with open(os.path.join(output_dir, "gsp_version.txt"), "w") as f:
+ f.write(version_str)
+
+# Extract signatures
+for i in range(3):
+ sig_section = program.getSection(f".fwsignature{i}")
+ if sig_section:
+ sig_data = getBytes(sig_section.getStart(), sig_section.getLength())
+ sig_path = os.path.join(output_dir, f"gsp-570.144.fwsignature{i}.bin")
+ with open(sig_path, "wb") as f:
+ f.write(sig_data)
+ print(f"Saved signature {i} to {sig_path} ({len(sig_data)} bytes)")
+
+# Create a new Ghidra project for the .fwimage binary
+print("Creating Ghidra project for .fwimage binary...")
+
+# We'll do this via a separate script call
+print("Done extracting sections.") \ No newline at end of file
diff --git a/tools/ghidra/gsp-tu104-570.144/scripts/extract_gsp_version.py b/tools/ghidra/gsp-tu104-570.144/scripts/extract_gsp_version.py
new file mode 100644
index 0000000..ef44d7d
--- /dev/null
+++ b/tools/ghidra/gsp-tu104-570.144/scripts/extract_gsp_version.py
@@ -0,0 +1,30 @@
+# Ghidra script to extract version from .fwversion section of GSP binary
+# Usage: analyzeHeadless ... -postScript extract_gsp_version.py
+
+import sys
+
+# Get the current program
+program = getCurrentProgram()
+
+# Get the .fwversion section
+fwversion_section = program.getSection(".fwversion")
+if fwversion_section:
+ # Get the data from the section
+ data = getBytes(fwversion_section.getStart(), fwversion_section.getLength())
+ version_str = data.decode('ascii').strip('\x00')
+ print(f"GSP Firmware Version: {version_str}")
+
+ # Also save to a file
+ with open("/home/rmcore/Git/integdev_gpu_drv/open-iov/tools/ghidra/gsp-tu104-570.144/gsp_version.txt", "w") as f:
+ f.write(version_str)
+else:
+ print("No .fwversion section found")
+
+ # Try to find version in memory
+ listing = program.getListing()
+ for i in range(listing.getNumAddresses()):
+ addr = listing.getAddress(i)
+ data = getBytes(addr, 32)
+ if data and b"570.144" in data:
+ print(f"Found version at {addr}: {data}")
+ break