diff options
Diffstat (limited to 'tools/ghidra')
| -rw-r--r-- | tools/ghidra/analyze_fwimage.py | 66 | ||||
| -rwxr-xr-x | tools/ghidra/analyze_gsp_firmware.sh | 97 | ||||
| -rw-r--r-- | tools/ghidra/create_gsp_project.py | 67 | ||||
| -rw-r--r-- | tools/ghidra/diff_gsp_firmware.py | 220 | ||||
| -rw-r--r-- | tools/ghidra/gsp-fwimage-570.144/scripts/BasicAnalysis.java | 156 | ||||
| -rw-r--r-- | tools/ghidra/gsp-fwimage-570.144/scripts/DecompileFunctions.java | 88 | ||||
| -rw-r--r-- | tools/ghidra/gsp-fwimage-570.144/scripts/ExtractFunctions.java | 126 | ||||
| -rw-r--r-- | tools/ghidra/gsp-fwimage-570.144/scripts/basic_analysis.py | 108 | ||||
| -rw-r--r-- | tools/ghidra/gsp-tu104-570.144/scripts/DecompileFunctions.java | 143 | ||||
| -rw-r--r-- | tools/ghidra/gsp-tu104-570.144/scripts/analyze_gsp_fwimage.py | 207 | ||||
| -rw-r--r-- | tools/ghidra/gsp-tu104-570.144/scripts/basic_analysis.py | 108 | ||||
| -rw-r--r-- | tools/ghidra/gsp-tu104-570.144/scripts/extract_fwimage.py | 56 | ||||
| -rw-r--r-- | tools/ghidra/gsp-tu104-570.144/scripts/extract_gsp_version.py | 30 |
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 |
