Overview

What is a Donor Dump?

A donor dump is a comprehensive snapshot of a physical PCI device’s configuration and capabilities. The PCILeech Firmware Generator uses this information to create firmware that accurately emulates the donor device’s behavior.

Key Information Captured:

Component Description Purpose
Device Identity Vendor/Device IDs, Subsystem IDs, Revision Device identification and driver matching
Configuration Space Full 4KB extended PCI configuration Complete device state and capabilities
Power Management MPC/MPR values, power states Power efficiency and compatibility
Capabilities AER, MSI/MSI-X, vendor-specific Advanced PCI features
Memory Layout BAR sizes, Device Serial Number (DSN) Memory mapping and addressing
Class Information 24-bit class code Device type classification

When to Use Manual Process

  • Debugging: When automated tools fail or produce unexpected results
  • Custom Workflows: Integration with existing automation or CI/CD pipelines
  • Research: Understanding the donor extraction process in detail
  • Troubleshooting: Isolating issues in the firmware generation pipeline

Prerequisites

System Requirements

Requirement Linux
OS Version Any modern distribution
Privileges Root access (sudo)
Shell Bash/Zsh
Build Tools GCC, Make, Kernel Headers

Quick Prerequisite Check

Linux:

# Check if all prerequisites are available
echo "Checking prerequisites..."
command -v gcc >/dev/null 2>&1 && echo "✓ GCC available" || echo "✗ GCC missing"
command -v make >/dev/null 2>&1 && echo "✓ Make available" || echo "✗ Make missing"
[ -d "/lib/modules/$(uname -r)/build" ] && echo "✓ Kernel headers available" || echo "✗ Kernel headers missing"
[ "$EUID" -eq 0 ] && echo "✓ Running as root" || echo "✗ Need root privileges"

Installing Prerequisites

Debian/Ubuntu

sudo apt-get update && sudo apt-get install -y \
    linux-headers-$(uname -r) \
    build-essential \
    dkms

Fedora/CentOS/RHEL

sudo dnf install -y \
    kernel-devel-$(uname -r) \
    gcc \
    make \
    dkms

Arch Linux/Manjaro

sudo pacman -S --needed \
    linux-headers \
    base-devel \
    dkms

openSUSE

sudo zypper install -y \
    kernel-devel-$(uname -r) \
    gcc \
    make \
    dkms

Linux Manual Process

Step 1: Device Discovery and Validation

Find Your Donor Device

# List all PCI devices with detailed information
lspci -vv

# Filter by device type (example: network controllers)
lspci -vv | grep -A 20 "Ethernet controller"

# Get specific device information
lspci -s 03:00.0 -vv

Validate Device Accessibility

# Check if device is bound to a driver
lspci -k -s 03:00.0

# Verify device is not in use by critical services
systemctl status NetworkManager  # For network devices
systemctl status display-manager # For graphics devices

Extract BDF Information

# Get BDF with domain information
DEVICE_BDF=$(lspci | grep "Ethernet controller" | head -1 | cut -d' ' -f1)
FULL_BDF="0000:${DEVICE_BDF}"
echo "Using device: ${FULL_BDF}"

Step 2: Build Environment Setup

# Ensure we're in the correct directory
cd "$(dirname "$0")/../PCILeechFWGenerator/src/donor_dump" || {
    echo "Error: Cannot find donor_dump directory"
    exit 1
}

# Verify required files exist
[ -f "Makefile" ] || { echo "Error: Makefile not found"; exit 1; }
[ -f "donor_dump.c" ] || { echo "Error: Source file not found"; exit 1; }

Clean Build Environment

# Clean any previous builds
make clean

# Verify kernel build environment
make -n 2>&1 | grep -q "No rule to make target" && {
    echo "Error: Kernel build environment not properly configured"
    exit 1
}

Build with Error Handling

# Build the kernel module with verbose output
if ! make V=1; then
    echo "Build failed. Common issues:"
    echo "1. Kernel headers mismatch: $(uname -r) vs $(ls /lib/modules/)"
    echo "2. Missing dependencies: gcc, make, kernel-devel"
    echo "3. Insufficient permissions"
    exit 1
fi

# Verify build artifacts
[ -f "donor_dump.ko" ] || { echo "Error: Module not built"; exit 1; }
echo "✓ Module built successfully: $(ls -lh donor_dump.ko)"

Step 3: Module Loading and Device Binding

Pre-load Validation

# Check if module is already loaded
if lsmod | grep -q donor_dump; then
    echo "Warning: donor_dump module already loaded"
    sudo rmmod donor_dump || {
        echo "Error: Cannot unload existing module"
        exit 1
    }
fi

# Verify device exists and is accessible
if ! lspci -s "${DEVICE_BDF}" >/dev/null 2>&1; then
    echo "Error: Device ${FULL_BDF} not found"
    exit 1
fi

Load Module with Comprehensive Error Handling

# Load module with device binding
if ! sudo insmod donor_dump.ko bdf="${FULL_BDF}"; then
    echo "Module load failed. Checking kernel logs..."
    dmesg | tail -20 | grep donor_dump
    exit 1
fi

# Verify module loaded successfully
if ! lsmod | grep -q donor_dump; then
    echo "Error: Module not loaded despite successful insmod"
    exit 1
fi

echo "✓ Module loaded successfully for device ${FULL_BDF}"

Verify Proc Interface

# Check if proc file is created and accessible
if [ ! -r "/proc/donor_dump" ]; then
    echo "Error: /proc/donor_dump not accessible"
    echo "Module may have loaded but device binding failed"
    sudo rmmod donor_dump
    exit 1
fi

echo "✓ Proc interface available"

Step 4: Data Extraction and Validation

Extract Raw Data

# Read donor information with error checking
if ! DONOR_DATA=$(cat /proc/donor_dump 2>/dev/null); then
    echo "Error: Cannot read donor information"
    sudo rmmod donor_dump
    exit 1
fi

# Validate data completeness
if [ -z "$DONOR_DATA" ]; then
    echo "Error: No donor data extracted"
    sudo rmmod donor_dump
    exit 1
fi

echo "✓ Donor data extracted ($(echo "$DONOR_DATA" | wc -l) lines)"

Save Raw Data with Metadata

# Create output directory with timestamp
OUTPUT_DIR="donor_dumps/$(date +%Y%m%d_%H%M%S)_${DEVICE_BDF//:/_}"
mkdir -p "$OUTPUT_DIR"

# Save raw data with metadata
{
    echo "# Donor dump generated on $(date)"
    echo "# Device: ${FULL_BDF}"
    echo "# Kernel: $(uname -r)"
    echo "# System: $(uname -a)"
    echo ""
    echo "$DONOR_DATA"
} > "${OUTPUT_DIR}/donor_info.txt"

echo "✓ Raw data saved to ${OUTPUT_DIR}/donor_info.txt"

Convert to JSON with Validation

# Enhanced JSON conversion with validation
convert_to_json() {
    local input_file="$1"
    local output_file="$2"
    
    # Create JSON with proper escaping and validation
    {
        echo "{"
        echo "  \"metadata\": {"
        echo "    \"generated_at\": \"$(date -Iseconds)\","
        echo "    \"device_bdf\": \"${FULL_BDF}\","
        echo "    \"kernel_version\": \"$(uname -r)\","
        echo "    \"generator_version\": \"manual-v1.0\""
        echo "  },"
        echo "  \"device_info\": {"
        
        # Process each line, handling special characters
        grep -v '^#' "$input_file" | while IFS=':' read -r key value; do
            if [ -n "$key" ] && [ -n "$value" ]; then
                # Escape special characters in JSON
                key=$(echo "$key" | sed 's/"/\\"/g' | xargs)
                value=$(echo "$value" | sed 's/"/\\"/g' | xargs)
                echo "    \"$key\": \"$value\","
            fi
        done | sed '$ s/,$//'  # Remove trailing comma
        
        echo "  }"
        echo "}"
    } > "$output_file"
    
    # Validate JSON syntax
    if command -v python3 >/dev/null 2>&1; then
        if ! python3 -m json.tool "$output_file" >/dev/null 2>&1; then
            echo "Warning: Generated JSON may be invalid"
            return 1
        fi
    fi
    
    return 0
}

# Convert to JSON
JSON_FILE="${OUTPUT_DIR}/donor_info.json"
if convert_to_json "${OUTPUT_DIR}/donor_info.txt" "$JSON_FILE"; then
    echo "✓ JSON file created: $JSON_FILE"
else
    echo "⚠ JSON conversion completed with warnings"
fi

Step 5: Cleanup and Verification

Safe Module Unloading

# Unload module with verification
cleanup_module() {
    if lsmod | grep -q donor_dump; then
        if sudo rmmod donor_dump; then
            echo "✓ Module unloaded successfully"
        else
            echo "Warning: Module unload failed"
            echo "Check: lsmod | grep donor_dump"
            echo "Force remove: sudo rmmod -f donor_dump"
        fi
    fi
}

# Set trap for cleanup on script exit
trap cleanup_module EXIT

Verify Output Quality

# Comprehensive output validation
validate_donor_dump() {
    local json_file="$1"
    
    echo "Validating donor dump quality..."
    
    # Check required fields
    local required_fields=("vendor_id" "device_id" "class_code")
    for field in "${required_fields[@]}"; do
        if ! grep -q "\"$field\"" "$json_file"; then
            echo "Warning: Missing required field: $field"
        fi
    done
    
    # Check file size (should be reasonable)
    local file_size=$(stat -f%z "$json_file" 2>/dev/null || stat -c%s "$json_file" 2>/dev/null)
    if [ "$file_size" -lt 100 ]; then
        echo "Warning: Donor dump seems too small ($file_size bytes)"
    elif [ "$file_size" -gt 10000 ]; then
        echo "Warning: Donor dump seems unusually large ($file_size bytes)"
    else
        echo "✓ Donor dump size looks reasonable ($file_size bytes)"
    fi
}

validate_donor_dump "$JSON_FILE"

Validation and Testing

Donor Dump Quality Validation

Comprehensive Validation Script

#!/bin/bash
# validate_donor_dump.sh - Comprehensive donor dump validation

validate_donor_dump() {
    local json_file="$1"
    local errors=0
    local warnings=0
    
    echo "=== Donor Dump Validation Report ==="
    echo "File: $json_file"
    echo "Generated: $(date)"
    echo ""
    
    # Check file existence and readability
    if [ ! -f "$json_file" ]; then
        echo "❌ ERROR: File does not exist"
        return 1
    fi
    
    if [ ! -r "$json_file" ]; then
        echo "❌ ERROR: File is not readable"
        return 1
    fi
    
    # Validate JSON syntax
    if command -v jq >/dev/null 2>&1; then
        if ! jq empty "$json_file" 2>/dev/null; then
            echo "❌ ERROR: Invalid JSON syntax"
            ((errors++))
        else
            echo "✓ JSON syntax valid"
        fi
    else
        echo "⚠ WARNING: jq not available, skipping JSON validation"
        ((warnings++))
    fi
    
    # Check required fields
    local required_fields=(
        ".device_info.vendor_id"
        ".device_info.device_id"
        ".metadata.device_bdf"
    )
    
    for field in "${required_fields[@]}"; do
        if command -v jq >/dev/null 2>&1; then
            if [ "$(jq -r "$field // empty" "$json_file")" = "" ]; then
                echo "❌ ERROR: Missing required field: $field"
                ((errors++))
            else
                echo "✓ Required field present: $field"
            fi
        fi
    done
    
    # Validate field formats
    if command -v jq >/dev/null 2>&1; then
        # Check vendor_id format (4 hex digits)
        vendor_id=$(jq -r '.device_info.vendor_id // empty' "$json_file")
        if [[ ! "$vendor_id" =~ ^[0-9A-Fa-f]{4}$ ]]; then
            echo "❌ ERROR: Invalid vendor_id format: $vendor_id"
            ((errors++))
        fi
        
        # Check device_id format (4 hex digits)
        device_id=$(jq -r '.device_info.device_id // empty' "$json_file")
        if [[ ! "$device_id" =~ ^[0-9A-Fa-f]{4}$ ]]; then
            echo "❌ ERROR: Invalid device_id format: $device_id"
            ((errors++))
        fi
        
        # Check BDF format
        bdf=$(jq -r '.metadata.device_bdf // empty' "$json_file")
        if [[ ! "$bdf" =~ ^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}\.[0-9A-Fa-f]$ ]]; then
            echo "⚠ WARNING: Unusual BDF format: $bdf"
            ((warnings++))
        fi
    fi
    
    # File size checks
    local file_size=$(stat -f%z "$json_file" 2>/dev/null || stat -c%s "$json_file" 2>/dev/null)
    if [ "$file_size" -lt 200 ]; then
        echo "⚠ WARNING: File seems small ($file_size bytes) - may be incomplete"
        ((warnings++))
    elif [ "$file_size" -gt 50000 ]; then
        echo "⚠ WARNING: File seems large ($file_size bytes) - may contain unexpected data"
        ((warnings++))
    fi
    
    echo ""
    echo "=== Validation Summary ==="
    echo "Errors: $errors"
    echo "Warnings: $warnings"
    
    if [ "$errors" -eq 0 ]; then
        echo "✅ Validation PASSED"
        return 0
    else
        echo "❌ Validation FAILED"
        return 1
    fi
}

# Usage: validate_donor_dump "path/to/donor_info.json"

Integration Testing

Test with PCILeech Generator

#!/bin/bash
# test_donor_integration.sh - Test donor dump with PCILeech

test_donor_integration() {
    local donor_file="$1"
    local test_board="${2:-pcileech_35t325_x1}"
    local test_bdf="${3:-0000:03:00.0}"
    
    echo "Testing donor dump integration..."
    
    # Validate donor file first
    if ! validate_donor_dump "$donor_file"; then
        echo "❌ Donor dump validation failed"
        return 1
    fi
    
    # Test dry-run with PCILeech generator
    if command -v pcileech-generate >/dev/null 2>&1; then
        echo "Testing with PCILeech generator (dry-run)..."
        if pcileech-generate \
            --bdf "$test_bdf" \
            --board "$test_board" \
            --donor-info-file "$donor_file" \
            --dry-run; then
            echo "✅ Integration test PASSED"
            return 0
        else
            echo "❌ Integration test FAILED"
            return 1
        fi
    else
        echo "⚠ PCILeech generator not available, skipping integration test"
        return 0
    fi
}

Troubleshooting

Common Issues and Solutions

Linux-Specific Issues

1. Kernel Headers Mismatch

# Problem: Headers don't match running kernel
# Solution: Install correct headers or use DKMS

# Check current kernel vs available headers
echo "Running kernel: $(uname -r)"
echo "Available headers:"
ls /lib/modules/*/build 2>/dev/null || echo "No headers found"

# Fix with DKMS (recommended)
sudo apt-get install dkms
sudo dkms add ./donor_dump
sudo dkms build donor_dump/1.0
sudo dkms install donor_dump/1.0

2. Module Loading Failures

# Comprehensive module debugging
debug_module_load() {
    local module_path="$1"
    local bdf="$2"
    
    echo "Debugging module load for $module_path with BDF $bdf"
    
    # Check module dependencies
    echo "Module info:"
    modinfo "$module_path"
    
    # Check for conflicting modules
    echo "Checking for conflicts:"
    lsmod | grep -E "(pci|donor)"
    
    # Attempt load with verbose logging
    echo "Loading with verbose logging:"
    sudo insmod "$module_path" bdf="$bdf" debug=1
    
    # Check kernel logs
    echo "Recent kernel messages:"
    dmesg | tail -20
}

3. Device Access Issues

# Check device binding and driver conflicts
check_device_binding() {
    local bdf="$1"
    
    echo "Device binding status for $bdf:"
    
    # Check current driver
    if [ -d "/sys/bus/pci/devices/$bdf" ]; then
        echo "Device exists in sysfs"
        
        if [ -L "/sys/bus/pci/devices/$bdf/driver" ]; then
            current_driver=$(readlink "/sys/bus/pci/devices/$bdf/driver" | xargs basename)
            echo "Current driver: $current_driver"
            
            # Suggest unbinding if necessary
            echo "To unbind: echo '$bdf' | sudo tee /sys/bus/pci/devices/$bdf/driver/unbind"
        else
            echo "No driver bound"
        fi
    else
        echo "❌ Device not found in sysfs"
    fi
}

Performance Optimization

Batch Processing Multiple Devices

#!/bin/bash
# batch_donor_dump.sh - Process multiple devices efficiently

batch_donor_dump() {
    local device_list="$1"  # File with one BDF per line
    local output_dir="$2"
    
    mkdir -p "$output_dir"
    
    # Build module once
    echo "Building donor_dump module..."
    if ! make -C src/donor_dump; then
        echo "❌ Module build failed"
        return 1
    fi
    
    # Process each device
    while IFS= read -r bdf; do
        [ -z "$bdf" ] && continue
        [[ "$bdf" =~ ^#.*$ ]] && continue  # Skip comments
        
        echo "Processing device: $bdf"
        
        # Create device-specific output directory
        device_dir="$output_dir/${bdf//:/_}"
        mkdir -p "$device_dir"
        
        # Load module for this device
        if sudo insmod src/donor_dump/donor_dump.ko bdf="$bdf"; then
            # Extract data
            cat /proc/donor_dump > "$device_dir/donor_info.txt"
            
            # Convert to JSON
            convert_to_json "$device_dir/donor_info.txt" "$device_dir/donor_info.json"
            
            # Unload module
            sudo rmmod donor_dump
            
            echo "✓ Completed: $bdf"
        else
            echo "❌ Failed: $bdf"
        fi
        
        # Brief pause to avoid overwhelming the system
        sleep 1
    done < "$device_list"
}

Advanced Usage

Custom Data Extraction

Extended Information Gathering

# Enhanced donor dump with additional system context
create_extended_donor_dump() {
    local bdf="$1"
    local output_file="$2"
    
    # Standard donor dump
    cat /proc/donor_dump > "${output_file}.raw"
    
    # Add system context
    {
        echo "=== EXTENDED DONOR DUMP ==="
        echo "Generated: $(date -Iseconds)"
        echo "System: $(uname -a)"
        echo "BDF: $bdf"
        echo ""
        
        echo "=== DEVICE INFORMATION ==="
        lspci -vvv -s "${bdf#0000:}"
        echo ""
        
        echo "=== SYSTEM PCI TREE ==="
        lspci -tv
        echo ""
        
        echo "=== IOMMU GROUPS ==="
        find /sys/kernel/iommu_groups/ -name "*" -type l | \
            xargs -I {} sh -c 'echo "Group $(basename $(dirname {})): $(basename $(readlink {}))"' | \
            grep "$bdf" || echo "No IOMMU group found"
        echo ""
        
        echo "=== DONOR DUMP DATA ==="
        cat "${output_file}.raw"
        
    } > "$output_file"
}

Automation Integration

CI/CD Pipeline Integration

# .github/workflows/donor-dump-validation.yml
name: Donor Dump Validation

on:
  push:
    paths:
      - 'donor_dumps/**'
      - 'src/donor_dump/**'

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y jq
          
      - name: Validate donor dumps
        run: |
          for dump in donor_dumps/*.json; do
            echo "Validating $dump"
            ./scripts/validate_donor_dump.sh "$dump"
          done

Security Considerations

Safe Module Handling

# Secure module loading with verification
secure_module_load() {
    local module_path="$1

Automation Integration

CI/CD Pipeline Integration

# .github/workflows/donor-dump-validation.yml
name: Donor Dump Validation

on:
  push:
    paths:
      - 'donor_dumps/**'
      - 'src/donor_dump/**'

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y jq
          
      - name: Validate donor dumps
        run: |
          for dump in donor_dumps/*.json; do
            echo "Validating $dump"
            ./scripts/validate_donor_dump.sh "$dump"
          done

Security Considerations

Safe Module Handling

# Secure module loading with verification
secure_module_load() {
    local module_path="$1"
    local bdf="$2"
    
    # Verify module signature (if available)
    if command -v modinfo >/dev/null 2>&1; then
        modinfo "$module_path" | grep -q "signature" && echo "✓ Module is signed"
    fi
    
    # Check module for suspicious content
    if command -v strings >/dev/null 2>&1; then
        if strings "$module_path" | grep -qE "(rm -rf|format|delete)"; then
            echo "⚠ WARNING: Module contains potentially dangerous strings"
            read -p "Continue anyway? (y/N): " -n 1 -r
            echo
            [[ ! $REPLY =~ ^[Yy]$ ]] && return 1
        fi
    fi
    
    # Load with restricted permissions
    sudo insmod "$module_path" bdf="$bdf"
}

Privilege Management

# Check and minimize required privileges
check_privileges() {
    if [ "$EUID" -ne 0 ]; then
        echo "This script requires root privileges for:"
        echo "- Loading kernel modules"
        echo "- Accessing PCI configuration space"
        echo "- Reading /proc interfaces"
        echo ""
        echo "Run with: sudo $0"
        exit 1
    fi
    
    # Drop privileges where possible
    if command -v sudo >/dev/null 2>&1; then
        ORIGINAL_USER="${SUDO_USER:-$USER}"
        echo "Running as root, will drop privileges where possible"
    fi
}

Best Practices Summary

Development Workflow

  1. Always validate prerequisites before starting
  2. Use version control for donor dump files
  3. Document device-specific quirks in metadata
  4. Test with multiple board types when possible
  5. Maintain backup copies of working donor dumps

Production Deployment

  1. Automate validation in CI/CD pipelines
  2. Use secure module signing in production
  3. Monitor for kernel compatibility issues
  4. Implement rollback procedures for failed dumps
  5. Log all operations for audit trails

Performance Optimization

  1. Batch process multiple devices when possible
  2. Cache build artifacts to avoid rebuilds
  3. Use parallel processing for validation
  4. Minimize module load/unload cycles
  5. Implement smart retry logic for transient failures

Conclusion

This enhanced manual donor dump generation guide provides:

  • Comprehensive error handling for robust operation
  • Cross-platform support for Linux and Windows
  • Validation and testing frameworks for quality assurance
  • Performance optimizations for batch processing
  • Security considerations for safe operation
  • Integration examples for automation workflows

The manual process gives you complete control over donor dump generation, making it ideal for:

  • Debugging automated tool failures
  • Research and development of new features
  • Custom integration with existing workflows
  • Educational purposes to understand the process

For most users, the automated pcileech.py command or TUI interface remains the recommended approach, but this manual process provides a powerful alternative when needed.

Quick Reference

Essential Commands

Linux:

# Quick donor dump
cd PCILeechFWGenerator/src/donor_dump
make && sudo insmod donor_dump.ko bdf=0000:03:00.0
cat /proc/donor_dump > donor_info.txt
sudo rmmod donor_dump

File Locations

Support Resources