summaryrefslogtreecommitdiffstats
path: root/docs/PORTABLE_ARCHITECTURE.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/PORTABLE_ARCHITECTURE.md')
-rw-r--r--docs/PORTABLE_ARCHITECTURE.md742
1 files changed, 742 insertions, 0 deletions
diff --git a/docs/PORTABLE_ARCHITECTURE.md b/docs/PORTABLE_ARCHITECTURE.md
new file mode 100644
index 0000000..47d0297
--- /dev/null
+++ b/docs/PORTABLE_ARCHITECTURE.md
@@ -0,0 +1,742 @@
+# Open-IOV vGPU-IO Portable Architecture Design
+
+## Design Goals
+
+### 1. Driver Version Portability
+- **Support NVIDIA OpenRM 550+** without code changes per version
+- **Automatic version detection** at runtime
+- **Backward/forward compatibility** for RPC interfaces
+- **Graceful degradation** when features unavailable
+
+### 2. Hardware Portability
+- **Support multiple GPU architectures**: Turing (TU102/TU104), Ampere (GA100/GA102), Hopper (GH100), Blackwell (GB202/GB203/GB100), future
+- **Support multiple form factors**: Consumer (RTX 3090/4090/5090), Data Center (A100/H100/B200), DGX Spark, DGX Station
+- **Automatic hardware detection** via PCI device IDs and firmware signatures
+- **Capability-based feature enablement**
+
+### 3. Zero Guest Modification
+- **Guest runs stock NVIDIA driver** from NVIDIA website
+- **No Open-IOV code in guest** kernel or userspace
+- **Standard VFIO/mdev interface** only
+
+---
+
+## Core Architecture: Three-Layer Abstraction
+
+```
+╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
+║ PORTABLE ARCHITECTURE LAYERS ║
+╠═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
+║ ║
+║ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║
+║ │ LAYER 1: HARDWARE ABSTRACTION LAYER (HAL) │ ║
+║ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║
+║ │ │ GpuArchitecture (abstract base) │ │ ║
+║ │ │ ├── detect(pci_dev) → GpuArchitecture* │ │ ║
+║ │ │ ├── get_pci_device_ids() → vector<DeviceID> │ │ ║
+║ │ │ ├── get_bar_layout() → BarLayout │ │ ║
+║ │ │ ├── get_gsp_firmware_info() → FirmwareInfo │ │ ║
+║ │ │ ├── get_rpc_dispatcher_addresses() → RpcAddresses │ │ ║
+║ │ │ ├── get_capabilities() → GpuCapabilities │ │ ║
+║ │ │ ├── create_rpc_handler(rpc_type) → RpcHandler* │ │ ║
+║ │ │ └── create_bar_emulator() → BarEmulator* │ │ ║
+║ │ │ │ │ ║
+║ │ │ Concrete Implementations (per architecture): │ │ ║
+║ │ │ ├── TuringArchitecture (TU102, TU104, TU106, TU116, TU117) │ │ ║
+║ │ │ ├── AmpereArchitecture (GA100, GA102, GA103, GA104, GA106, GA107) │ │ ║
+║ │ │ ├── HopperArchitecture (GH100, GH200) │ │ ║
+║ │ │ ├── BlackwellArchitecture (GB202, GB203, GB205, GB206, GB100) │ │ ║
+║ │ │ └── FutureArchitecture (auto-generated from firmware analysis) │ │ ║
+║ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║
+║ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║
+║ ║
+║ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║
+║ │ LAYER 2: VERSION ADAPTATION LAYER (VAL) │ ║
+║ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║
+║ │ │ DriverVersion (semantic: major.minor.patch) │ │ ║
+║ │ │ ├── parse(version_string) → DriverVersion │ │ ║
+║ │ │ ├── is_compatible(min_version, max_version) → bool │ │ ║
+║ │ │ ├── get_rpc_interface_version() → RpcInterfaceVersion │ │ ║
+║ │ │ ├── get_firmware_signature() → string (SHA256 of firmware) │ │ ║
+║ │ │ └── get_feature_flags() → FeatureFlags │ │ ║
+║ │ │ │ │ ║
+║ │ │ RpcInterfaceVersion (per driver version): │ │ ║
+║ │ │ ├── get_rpc_type_count() → int │ │ ║
+║ │ │ ├── get_rpc_struct_layout(rpc_type) → StructLayout │ │ ║
+║ │ │ ├── get_subcommand_mapping() → SubcommandMap │ │ ║
+║ │ │ ├── get_error_codes() → ErrorCodeMap │ │ ║
+║ │ │ └── get_capability_bits() → CapabilityBits │ │ ║
+║ │ │ │ │ ║
+║ │ │ Version Registry (loaded at runtime): │ │ ║
+║ │ │ ├── 550.x → RpcInterfaceV1 │ │ ║
+║ │ │ ├── 560.x → RpcInterfaceV2 (added MIGRATE subcommands) │ │ ║
+║ │ │ ├── 570.x → RpcInterfaceV3 (added DEBUG, NOTIFY enhancements) │ │ ║
+║ │ │ ├── 580.x → RpcInterfaceV4 (confidential computing, TEE) │ │ ║
+║ │ │ └── auto-detect from firmware signature │ │ ║
+║ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║
+║ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║
+║ ║
+║ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║
+║ │ LAYER 3: FIRMWARE-DRIVEN RPC ENGINE (FDRE) │ ║
+║ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║
+║ │ │ FirmwareAnalyzer (runs at module load) │ │ ║
+║ │ │ ├── load_firmware(firmware_path) → FirmwareImage │ │ ║
+║ │ │ ├── find_rpc_dispatcher() → address │ │ ║
+║ │ │ ├── find_jump_table() → address │ │ ║
+║ │ │ ├── find_handler_addresses() → map<rpc_type, address> │ │ ║
+║ │ │ ├── extract_struct_layouts() → map<rpc_type, StructLayout> │ │ ║
+║ │ │ ├── compute_firmware_signature() → SHA256 │ │ ║
+║ │ │ └── validate_against_known_versions() → DriverVersion │ │ ║
+║ │ │ │ │ ║
+║ │ │ DynamicRpcDispatcher: │ │ ║
+║ │ │ ├── dispatch(rpc_msg) → uses discovered handler addresses │ │ ║
+║ │ │ ├── fallback_to_emulation(rpc_type) → if handler not found │ │ ║
+║ │ │ └── hot_patch_handler(rpc_type, new_address) → for live updates │ │ ║
+║ │ │ │ │ ║
+║ │ │ EmulationFallbackRegistry: │ │ ║
+║ │ │ ├── register_emulation(rpc_type, EmulationHandler*) │ │ ║
+║ │ │ ├── get_emulation(rpc_type) → EmulationHandler* │ │ ║
+║ │ │ └── supports_emulation(rpc_type) → bool │ │ ║
+║ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║
+║ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║
+║ ║
+╚════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
+```
+
+---
+
+## Configuration-Driven Design
+
+### 1. Hardware Configuration Files
+
+```yaml
+# config/hardware/turing.yaml
+architecture: "turing"
+pci_device_ids:
+ - vendor: 0x10de
+ device: 0x1e07 # TU102
+ name: "RTX 2080 Ti"
+ - vendor: 0x10de
+ device: 0x1e08 # TU104
+ name: "RTX 2080 / T4"
+ - vendor: 0x10de
+ device: 0x1ed3 # TU104 mobile
+ name: "RTX 2080 Super Mobile"
+bar_layout:
+ bar0_size: 16MB
+ bar1_size: 256MB
+ bar2_size: 32MB
+ bar3_size: 32MB
+ bar0_prefetchable: true
+ bar1_prefetchable: true
+gsp:
+ firmware_base: 0x04000000
+ doorbell_offset: 0x110C00
+ shared_mem_offset: 0x1000
+ shared_mem_size: 4KB
+ rpc_dispatcher_primary: 0x057A1AC0
+ rpc_dispatcher_secondary: 0x04ED39DC
+ rpc_jump_table: 0x059BFEB0
+ handlers:
+ alloc: 0x057E94EC
+ schedule: 0x051EFBF4
+ bar_trap: 0x04CB8188
+ wpr_1: 0x04F00B0C
+ wpr_2: 0x04F00C78
+ migration_table_1: 0x04179ED8
+ migration_table_2: 0x04179FBC
+capabilities:
+ max_vfs: 7
+ supports_mig: true
+ supports_wpr: true
+ supports_bar_trap: true
+ supports_scheduling: true
+ supports_notifications: true
+ msi_x_vectors: 32
+```
+
+```yaml
+# config/hardware/ampere.yaml
+architecture: "ampere"
+pci_device_ids:
+ - vendor: 0x10de
+ device: 0x20b0 # GA100
+ name: "A100"
+ - vendor: 0x10de
+ device: 0x2204 # GA102
+ name: "RTX 3090"
+ - vendor: 0x10de
+ device: 0x2206 # GA102
+ name: "RTX 3080"
+bar_layout:
+ bar0_size: 16MB
+ bar1_size: 512MB # Larger FB on Ampere
+ bar2_size: 64MB
+ bar3_size: 64MB
+gsp:
+ firmware_base: 0x04000000
+ doorbell_offset: 0x110C00
+ shared_mem_offset: 0x1000
+ # Addresses discovered at runtime via FirmwareAnalyzer
+capabilities:
+ max_vfs: 7
+ supports_mig: true
+ supports_mig_mig: true # MIG (Multi-Instance GPU)
+ supports_confidential: false
+ supports_wpr: true
+ supports_bar_trap: true
+ msi_x_vectors: 64
+```
+
+```yaml
+# config/hardware/blackwell.yaml
+architecture: "blackwell"
+pci_device_ids:
+ - vendor: 0x10de
+ device: 0x2480 # GB202 (RTX 5090)
+ name: "RTX 5090"
+ - vendor: 0x10de
+ device: 0x2380 # GB100 (B200)
+ name: "B200"
+ - vendor: 0x10de
+ device: 0x2384 # GB205
+ name: "RTX 5070"
+bar_layout:
+ bar0_size: 16MB
+ bar1_size: 1GB # Blackwell unified memory
+ bar2_size: 128MB
+ bar3_size: 128MB
+gsp:
+ firmware_base: 0x04000000
+ doorbell_offset: 0x110C00
+ shared_mem_offset: 0x1000
+capabilities:
+ max_vfs: 8
+ supports_mig: true
+ supports_mig_mig: true
+ supports_confidential: true # TEE support
+ supports_wpr: true
+ supports_bar_trap: true
+ supports_nvlink: true
+ msi_x_vectors: 128
+```
+
+### 2. Driver Version Configuration
+
+```yaml
+# config/versions/550.yaml
+version: "550"
+rpc_interface_version: 1
+rpc_types:
+ - ALLOC: 0x01
+ - FREE: 0x02
+ - MAP: 0x03
+ - UNMAP: 0x04
+ - PIN: 0x05
+ - UNPIN: 0x06
+ - SCHEDULE: 0x07
+ - YIELD: 0x08
+ - NOTIFY: 0x09
+ - BAR_TRAP: 0x0A
+ - MIGRATE: 0x0B
+ - DEBUG: 0x0C
+struct_layouts:
+ ALLOC:
+ size: 48
+ fields:
+ - {name: size, offset: 0, type: u64}
+ - {name: alignment, offset: 8, type: u64}
+ - {name: mem_type, offset: 16, type: u32}
+ - {name: flags, offset: 20, type: u32}
+ - {name: addr_hint, offset: 24, type: u64}
+ - {name: pid, offset: 32, type: u32}
+capabilities:
+ supports_migrate: true
+ migrate_subcommands:
+ - SAVE: 0x04
+ - RESTORE: 0x05
+ supports_notifications: basic
+```
+
+```yaml
+# config/versions/570.yaml
+version: "570"
+rpc_interface_version: 3
+extends: "550"
+rpc_types:
+ - NOTIFY: 0x09 # Enhanced with subcommands
+ - MIGRATE: 0x0B # Enhanced with 4-phase
+struct_layouts:
+ NOTIFY:
+ size: 32
+ fields:
+ - {name: type, offset: 0, type: u32}
+ - {name: subcmd, offset: 4, type: u32}
+ - {name: event_fd, offset: 8, type: u64}
+ - {name: flags, offset: 16, type: u32}
+capabilities:
+ supports_notifications: enhanced
+ supports_migrate_4phase: true
+ migrate_phases: [QUERY, PREPARE, TRANSFER, COMMIT, CLEANUP]
+```
+
+```yaml
+# config/versions/580.yaml
+version: "580"
+rpc_interface_version: 4
+extends: "570"
+rpc_types:
+ - TEE_ATTEST: 0x0D # New in 580 for confidential computing
+ - TEE_SEAL: 0x0E
+ - TEE_UNSEAL: 0x0F
+capabilities:
+ supports_confidential: true
+ supports_tee: true
+ tee_attestation_types: [CPU, GPU, MEMORY]
+```
+
+---
+
+## Runtime Detection & Adaptation Flow
+
+```
+┌─────────────────────────────────────────────────────────────────────────────────────┐
+│ MODULE LOAD: RUNTIME DETECTION FLOW │
+├─────────────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ 1. open-iov-vfio.ko loads │
+│ │ │
+│ ▼ │
+│ 2. Probe PCI device │
+│ │ │
+│ ▼ │
+│ 3. Match PCI Device ID → Hardware Config (turing.yaml, ampere.yaml, etc.) │
+│ │ │
+│ ▼ │
+│ 4. Load Hardware Config → Instantiate GpuArchitecture subclass │
+│ │ │
+│ ▼ │
+│ 5. Load GSP Firmware (from /lib/firmware or host nvidia.ko) │
+│ │ │
+│ ▼ │
+│ 6. FirmwareAnalyzer.analyze(firmware) │
+│ ├── Compute firmware SHA256 │
+│ ├── Find RPC dispatcher via pattern matching │
+│ ├── Find jump table via cross-references │
+│ ├── Extract handler addresses for all 12+ RPC types │
+│ ├── Extract struct layouts via pattern matching │
+│ └── Match firmware signature → DriverVersion (550, 560, 570, 580, etc.) │
+│ │ │
+│ ▼ │
+│ 7. Load Version Config → Instantiate RpcInterfaceVersion │
+│ │ │
+│ ▼ │
+│ 8. Validate: Hardware Config + Version Config compatible? │
+│ │ │
+│ ├── YES → Initialize DynamicRpcDispatcher with discovered addresses │
+│ ├── PARTIAL → Enable emulation for missing handlers │
+│ └── NO → Fail with clear error: "Unsupported GPU/driver combination" │
+│ │ │
+│ ▼ │
+│ 9. Register EmulationFallbackRegistry for all RPC types │
+│ │ │
+│ ▼ │
+│ 10. Start GSP Emulation Thread (per mdev) │
+│ │
+└─────────────────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## FirmwareAnalyzer - Automatic Address Discovery
+
+```c
+// kernel/firmware_analyzer.c
+
+struct firmware_signature {
+ uint8_t sha256[32];
+ char version_string[64];
+ uint32_t crc32;
+};
+
+struct discovered_rpc_handlers {
+ uint64_t primary_dispatcher;
+ uint64_t secondary_dispatcher;
+ uint64_t jump_table;
+ struct {
+ uint32_t rpc_type;
+ uint64_t handler_address;
+ bool found;
+ } handlers[16]; // Support up to 16 RPC types
+ uint32_t handler_count;
+};
+
+struct firmware_analyzer {
+ const uint8_t *firmware;
+ size_t firmware_size;
+ uint64_t firmware_base;
+ struct discovered_rpc_handlers discovered;
+ struct firmware_signature signature;
+};
+
+int firmware_analyzer_init(struct firmware_analyzer *fa, const char *firmware_path) {
+ // Load firmware file
+ fa->firmware = load_firmware_file(firmware_path, &fa->firmware_size);
+ if (!fa->firmware)
+ return -ENOENT;
+
+ // Compute signature
+ sha256(fa->firmware, fa->firmware_size, fa->signature.sha256);
+ fa->signature.crc32 = crc32(0, fa->firmware, fa->firmware_size);
+
+ // Set base address (from hardware config)
+ fa->firmware_base = get_hardware_config()->gsp.firmware_base;
+
+ return 0;
+}
+
+int firmware_analyzer_discover(struct firmware_analyzer *fa) {
+ // 1. Find primary dispatcher: search for known pattern
+ // Pattern: "RPC_DISPATCH" string reference or known instruction sequence
+ fa->discovered.primary_dispatcher = find_pattern(fa->firmware, fa->firmware_size,
+ "RPC_DISPATCH", fa->firmware_base);
+
+ // 2. Find jump table: cross-reference from dispatcher
+ fa->discovered.jump_table = find_jump_table(fa->firmware, fa->firmware_size,
+ fa->discovered.primary_dispatcher);
+
+ // 3. Parse jump table entries (32 entries for 12 RPC types)
+ parse_jump_table(fa->firmware, fa->discovered.jump_table, &fa->discovered);
+
+ // 4. Find secondary dispatcher
+ fa->discovered.secondary_dispatcher = find_secondary_dispatcher(fa->firmware,
+ fa->firmware_size, fa->discovered.primary_dispatcher);
+
+ // 5. Find specialized handlers via string references
+ find_handler_by_string(fa, "BAR_TRAP", "BAR1", "ForceBarAccess", &fa->discovered.handlers[GSP_RPC_BAR_TRAP]);
+ find_handler_by_string(fa, "WPR", "completion", "timeout", &fa->discovered.handlers[GSP_RPC_NOTIFY]);
+ find_handler_by_string(fa, "ALLOC", "size", "alignment", &fa->discovered.handlers[GSP_RPC_ALLOC]);
+ find_handler_by_string(fa, "SCHEDULE", "work", "callback", &fa->discovered.handlers[GSP_RPC_SCHEDULE]);
+ find_handler_by_string(fa, "MIGRATE", "checkpoint", "progress", &fa->discovered.handlers[GSP_RPC_MIGRATE]);
+
+ // 6. Extract struct layouts via pattern matching on handler prologues
+ extract_struct_layouts(fa);
+
+ // 7. Match signature against known versions
+ match_firmware_version(fa);
+
+ return 0;
+}
+
+void firmware_analyzer_match_version(struct firmware_analyzer *fa) {
+ // Compare signature against known database
+ static const struct {
+ const char *version;
+ uint8_t sha256[32];
+ uint32_t crc32;
+ } known_versions[] = {
+ {"550.163.01", {0x...}, 0x...},
+ {"560.28.03", {0x...}, 0x...},
+ {"570.144.00", {0x...}, 0x...},
+ {"570.144.01", {0x...}, 0x...},
+ {"580.00.00", {0x...}, 0x...},
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(known_versions); i++) {
+ if (memcmp(fa->signature.sha256, known_versions[i].sha256, 32) == 0) {
+ strncpy(fa->signature.version_string, known_versions[i].version, 63);
+ return;
+ }
+ }
+
+ // Unknown version - use heuristic based on handler count and features
+ if (fa->discovered.handler_count >= 12)
+ strcpy(fa->signature.version_string, "570+ (unknown)");
+ else if (fa->discovered.handler_count >= 10)
+ strcpy(fa->signature.version_string, "560+ (unknown)");
+ else
+ strcpy(fa->signature.version_string, "550+ (unknown)");
+}
+```
+
+---
+
+## Dynamic RPC Dispatcher
+
+```c
+// kernel/dynamic_rpc_dispatcher.c
+
+struct dynamic_rpc_dispatcher {
+ struct discovered_rpc_handlers *discovered;
+ struct rpc_interface_version *interface;
+ struct emulation_fallback_registry *fallbacks;
+ spinlock_t lock;
+ uint64_t dispatch_stats[16];
+};
+
+int dynamic_rpc_dispatcher_dispatch(struct dynamic_rpc_dispatcher *dr,
+ struct gsp_rpc_msg *req,
+ struct gsp_rpc_response *rsp) {
+ // 1. Validate RPC type
+ if (req->type >= dr->interface->rpc_type_count)
+ return -ENOTTY;
+
+ // 2. Check if we have a native handler address
+ uint64_t handler_addr = 0;
+ for (int i = 0; i < dr->discovered->handler_count; i++) {
+ if (dr->discovered->handlers[i].rpc_type == req->type) {
+ handler_addr = dr->discovered->handlers[i].handler_address;
+ break;
+ }
+ }
+
+ // 3. Dispatch to native handler if available
+ if (handler_addr) {
+ return dynamic_rpc_call_native(dr, handler_addr, req, rsp);
+ }
+
+ // 4. Fallback to emulation
+ struct emulation_handler *emu = emulation_fallback_get(dr->fallbacks, req->type);
+ if (emu) {
+ dr->dispatch_stats[req->type]++; // Track emulation usage
+ return emu->handle(req, rsp);
+ }
+
+ // 5. No handler, no emulation
+ rsp->status = -ENOTTY;
+ return -ENOTTY;
+}
+
+int dynamic_rpc_call_native(struct dynamic_rpc_dispatcher *dr,
+ uint64_t handler_addr,
+ struct gsp_rpc_msg *req,
+ struct gsp_rpc_response *rsp) {
+ // Use firmware-decompiled calling convention
+ // This calls the actual GSP firmware handler via the discovered address
+ // In emulation mode, we call our C reimplementation instead
+
+ if (gsp_emulation_mode_enabled()) {
+ // Call our C reimplementation (from gsp_rpc_client.c)
+ return gsp_rpc_client_call(req->type, req, rsp);
+ } else {
+ // Native mode: would call into GSP firmware
+ // Not used in our architecture (we always emulate in host)
+ return -ENOTSUPP;
+ }
+}
+```
+
+---
+
+## Capability Negotiation with Guest
+
+```
+┌─────────────────────────────────────────────────────────────────────────────────────┐
+│ GUEST DRIVER CAPABILITY NEGOTIATION │
+├─────────────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Guest nvidia.ko probes vGPU: │
+│ 1. Reads PCI Config Space → gets device ID, BAR sizes, capabilities │
+│ 2. Maps BAR0 → finds GSP doorbell + shared memory │
+│ 3. Sends RPC: QUERY_CAPABILITIES (new RPC type or subcommand) │
+│ │
+│ Host DynamicRpcDispatcher receives QUERY_CAPABILITIES: │
+│ 1. Constructs response from: │
+│ - Hardware Config capabilities │
+│ - Version Config capabilities │
+│ - EmulationFallbackRegistry (what we can emulate) │
+│ 2. Returns capability bitmap to guest │
+│ │
+│ Guest nvidia.ko enables features based on response: │
+│ - If MIG supported → enables MIG code paths │
+│ - If WPR supported → enables WPR code paths │
+│ - If CONFIDENTIAL supported → enables TEE code paths │
+│ - If NOTIFY enhanced → uses async eventfd │
+│ │
+│ This allows SAME guest driver to work across ALL hardware/versions! │
+│ │
+└─────────────────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Update Strategy for New Driver Versions
+
+### 1. Adding New Driver Version (e.g., 590)
+
+```bash
+# 1. Add version config
+cp config/versions/580.yaml config/versions/590.yaml
+# Edit: version, rpc_interface_version, new RPC types, capabilities
+
+# 2. Test with new firmware
+# FirmwareAnalyzer auto-discovers addresses - NO CODE CHANGES NEEDED
+
+# 3. If new RPC types added:
+# - Add to config/versions/590.yaml
+# - Add emulation handler in kernel/emulation_fallbacks.c
+# - Register in EmulationFallbackRegistry
+
+# 4. If struct layouts changed:
+# - FirmwareAnalyzer extracts new layouts automatically
+# - Version config specifies layout version
+```
+
+### 2. Adding New GPU Architecture (e.g., Rubin R100)
+
+```bash
+# 1. Add hardware config
+cp config/hardware/blackwell.yaml config/hardware/rubin.yaml
+# Edit: PCI device IDs, BAR layout, capabilities
+
+# 2. Add GpuArchitecture subclass (if special handling needed)
+# kernel/arch/rubin_architecture.c
+
+# 3. Register in architecture factory
+# kernel/architecture_factory.c
+
+# 4. Test - FirmwareAnalyzer handles address discovery
+```
+
+### 3. Automated Firmware Analysis Pipeline
+
+```yaml
+# .github/workflows/firmware-analysis.yml
+name: Firmware Analysis
+on:
+ schedule:
+ - cron: '0 0 * * 0' # Weekly
+ workflow_dispatch:
+ inputs:
+ firmware_url:
+ description: 'NVIDIA firmware download URL'
+ required: true
+
+jobs:
+ analyze:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Download firmware
+ run: wget -O firmware.bin "${{ inputs.firmware_url }}"
+ - name: Run FirmwareAnalyzer
+ run: |
+ ./tools/firmware_analyzer firmware.bin > analysis.json
+ - name: Compare with known versions
+ run: ./tools/compare_analysis.py analysis.json
+ - name: Generate config if new
+ run: |
+ if [ "$(cat analysis.json | jq -r '.is_new')" = "true" ]; then
+ ./tools/generate_config.py analysis.json > config/versions/NEW.yaml
+ git add config/versions/NEW.yaml
+ git commit -m "Add support for new firmware version"
+ git push
+ fi
+```
+
+---
+
+## Testing Matrix for Portability
+
+| GPU Architecture | PCI Device IDs | Driver Versions | Test Status |
+|------------------|----------------|-----------------|-------------|
+| **Turing** | 10de:1e07, 10de:1e08, 10de:1ed3 | 550, 560, 570, 580 | ✅ Baseline |
+| **Ampere** | 10de:20b0, 10de:2204, 10de:2206 | 550, 560, 570, 580 | 🔄 In Progress |
+| **Hopper** | 10de:2330, 10de:2334 | 560, 570, 580 | 🔄 Planned |
+| **Blackwell** | 10de:2480, 10de:2380, 10de:2384 | 570, 580 | 🔄 Planned |
+| **Rubin (Future)** | TBD | 590+ | 📋 Designed |
+
+### Per-Combination Tests
+
+```bash
+# Automated test matrix
+for arch in turing ampere hopper blackwell; do
+ for version in 550 560 570 580; do
+ if [ -f "config/hardware/${arch}.yaml" ] && [ -f "config/versions/${version}.yaml" ]; then
+ echo "Testing ${arch} + ${version}..."
+ ./scripts/test_combination.sh ${arch} ${version}
+ fi
+ done
+done
+```
+
+---
+
+## Implementation File Structure (Portable)
+
+```
+open-iov/
+├── config/
+│ ├── hardware/
+│ │ ├── turing.yaml
+│ │ ├── ampere.yaml
+│ │ ├── hopper.yaml
+│ │ ├── blackwell.yaml
+│ │ └── rubin.yaml (future)
+│ ├── versions/
+│ │ ├── 550.yaml
+│ │ ├── 560.yaml
+│ │ ├── 570.yaml
+│ │ ├── 580.yaml
+│ │ └── 590.yaml (future)
+│ └── defaults.yaml
+├── kernel/
+│ ├── architecture/
+│ │ ├── architecture.h # Abstract base class
+│ │ ├── architecture_factory.c # Detection & instantiation
+│ │ ├── turing_architecture.c
+│ │ ├── ampere_architecture.c
+│ │ ├── hopper_architecture.c
+│ │ ├── blackwell_architecture.c
+│ │ └── generic_architecture.c # Fallback
+│ ├── version/
+│ │ ├── version.h # DriverVersion, RpcInterfaceVersion
+│ │ ├── version_registry.c # Loads version configs
+│ │ ├── interface_v1.c # 550 interface
+│ │ ├── interface_v2.c # 560 interface
+│ │ ├── interface_v3.c # 570 interface
+│ │ └── interface_v4.c # 580 interface
+│ ├── firmware/
+│ │ ├── firmware_analyzer.c # Auto-discovers addresses
+│ │ ├── firmware_analyzer.h
+│ │ ├── pattern_matcher.c # Binary pattern matching
+│ │ └── struct_layout_extractor.c
+│ ├── dispatch/
+│ │ ├── dynamic_rpc_dispatcher.c
+│ │ ├── dynamic_rpc_dispatcher.h
+│ │ ├── emulation_fallback_registry.c
+│ │ └── emulation_fallback_registry.h
+│ ├── gsp_emulation.c # Uses dynamic dispatcher
+│ ├── main.c # Integrates all layers
+│ └── Makefile
+├── tools/
+│ ├── firmware_analyzer/ # Standalone analysis tool
+│ ├── compare_analysis.py
+│ ├── generate_config.py
+│ └── test_combination.sh
+└── docs/
+ ├── PORTABLE_ARCHITECTURE.md
+ └── VERSION_COMPATIBILITY.md
+```
+
+---
+
+## Key Design Principles Summary
+
+| Principle | Implementation |
+|-----------|----------------|
+| **No hardcoded addresses** | FirmwareAnalyzer discovers at runtime |
+| **No hardcoded struct layouts** | Version config + FirmwareAnalyzer extraction |
+| **No hardcoded device IDs** | Hardware config YAML files |
+| **No hardcoded capabilities** | Capability negotiation via QUERY_CAPABILITIES RPC |
+| **Graceful degradation** | EmulationFallbackRegistry for missing handlers |
+| **Forward compatibility** | Version config `extends` mechanism |
+| **Automated updates** | Firmware analysis pipeline + config generation |
+| **Test matrix** | Automated CI across architecture × version combinations |
+
+---
+
+*Document Version: 1.0*
+*Repository: $OPEN_IOV_ROOT*
+*Branch: refactor/host-gsp-emulation*
+*Base Commit: f9ed5d8* \ No newline at end of file