<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://open-iov.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=WikiBot</id>
	<title>Open-IOV - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://open-iov.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=WikiBot"/>
	<link rel="alternate" type="text/html" href="https://open-iov.org/index.php/Special:Contributions/WikiBot"/>
	<updated>2026-10-12T06:50:17Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>https://open-iov.org/index.php?title=GPU_Software_Bill_Of_Materials_(SBOM)&amp;diff=23994</id>
		<title>GPU Software Bill Of Materials (SBOM)</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=GPU_Software_Bill_Of_Materials_(SBOM)&amp;diff=23994"/>
		<updated>2026-10-12T04:41:23Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
{{Superseded}}&lt;br /&gt;
= GPU Software Bill Of Materials (SBOM) =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''This page is superseded.''' The previous content was an imported 2023 wiki survey of third-party GPU-virtualization components. The complete, repository-scoped SBOM now lives at:&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''[https://git.vgpu.io/open-iov.git/tree/SBOM.md &amp;lt;code&amp;gt;SBOM.md&amp;lt;/code&amp;gt;]''' — human-readable SBOM: primary component, first-party components, bundled third-party components with SHA-256 hashes, archived-documentation provenance, external build/run dependencies, dependency graph, license/redistribution terms, and the NTIA minimum-elements checklist.&lt;br /&gt;
* '''[https://git.vgpu.io/open-iov.git/tree/sbom/open-iov-0.1.0.cdx.json &amp;lt;code&amp;gt;sbom/open-iov-0.1.0.cdx.json&amp;lt;/code&amp;gt;]''' — machine-readable CycloneDX 1.6 SBOM (serial &amp;lt;code&amp;gt;urn:uuid:e626c5a1-9697-4546-bb2b-5b4feb58e922&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The SBOM covers every file tracked in this repository plus the external components required to build, run and support it. NVIDIA drivers, GSP firmware and CUDA packages are documented but '''not distributed''' here.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=VGPU-IO_Integration_Guide&amp;diff=23993</id>
		<title>VGPU-IO Integration Guide</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=VGPU-IO_Integration_Guide&amp;diff=23993"/>
		<updated>2026-10-12T04:41:03Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= vGPU-IO Integration Guide =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' This earlier integration design predates the current stack and is retained for reference only. Canonical documentation: getting started [https://git.vgpu.io/open-iov.git/tree/docs/02-getting-started &amp;lt;code&amp;gt;../docs/02-getting-started/&amp;lt;/code&amp;gt;], host module [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;], developer standards [https://git.vgpu.io/open-iov.git/tree/docs/07-developers &amp;lt;code&amp;gt;../docs/07-developers/&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
This guide covers implementing a Linux kernel driver for vGPU-IO using the GSP 570.144W firmware RPC interface.&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;┌─────────────────────────────────────────────────────────────┐&lt;br /&gt;
│                    vGPU-IO Kernel Driver                     │&lt;br /&gt;
├─────────────────────────────────────────────────────────────┤&lt;br /&gt;
│  gsp_core.c      │  gsp_rpc.c    │  gsp_vf.c               │&lt;br /&gt;
│  - Device probe  │  - RPC client │  - VF lifecycle         │&lt;br /&gt;
│  - BAR mapping   │  - Doorbell   │  - Migration            │&lt;br /&gt;
│  - IRQ/MSI-X     │  - Completion │  - WPR/BAR integration  │&lt;br /&gt;
├─────────────────────────────────────────────────────────────┤&lt;br /&gt;
│                    GSP Firmware (570.144W)                   │&lt;br /&gt;
│  Primary Dispatcher (0x057A1AC0)  │  Secondary (0x04ED39DC) │&lt;br /&gt;
│  BAR Handler (0x04CB8188)         │  WPR Handlers           │&lt;br /&gt;
│  Migration (0x04179ED8/0x04179FBC)│  SCHED/ALLOC/PIN        │&lt;br /&gt;
└─────────────────────────────────────────────────────────────┘&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module Structure ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;drivers/gpu/nvidia/gsp/&lt;br /&gt;
├── gsp.h              # Core definitions&lt;br /&gt;
├── gsp_rpc.h          # RPC message formats&lt;br /&gt;
├── gsp_vf.h           # VF definitions&lt;br /&gt;
├── gsp_bar.h          # BAR emulation&lt;br /&gt;
├── gsp_wpr.h          # WPR management&lt;br /&gt;
├── gsp_migration.h    # Migration protocol&lt;br /&gt;
├── gsp_core.c         # Probe/remove, BAR/IRQ&lt;br /&gt;
├── gsp_rpc.c          # RPC client implementation&lt;br /&gt;
├── gsp_vf.c           # VF create/destroy&lt;br /&gt;
├── gsp_bar.c          # BAR trap handler&lt;br /&gt;
├── gsp_wpr.c          # WPR protect/unprotect&lt;br /&gt;
├── gsp_migration.c    # Live migration&lt;br /&gt;
└── gsp_debugfs.c      # Debug interface&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Core Data Structures ==&lt;br /&gt;
&lt;br /&gt;
=== GSP Device ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct gsp_device {&lt;br /&gt;
    struct pci_dev *pdev;&lt;br /&gt;
    void __iomem *bar0;           // PCIe BAR0 mapping&lt;br /&gt;
    void __iomem *bar1;           // PCIe BAR1 (GSP FW)&lt;br /&gt;
    struct gsp_firmware *fw;      // Firmware image&lt;br /&gt;
    struct gsp_rpc_client *rpc;   // RPC client&lt;br /&gt;
    struct mutex vf_lock;&lt;br /&gt;
    struct idr vf_idr;            // VF ID allocator&lt;br /&gt;
    struct list_head vf_list;&lt;br /&gt;
    struct gsp_debugfs *debugfs;&lt;br /&gt;
    spinlock_t doorbell_lock;&lt;br /&gt;
    uint32_t doorbell_seq;&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== VF (Virtual Function) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct gsp_vf {&lt;br /&gt;
    struct gsp_device *gsp;&lt;br /&gt;
    uint32_t id;                  // VF ID (1-7)&lt;br /&gt;
    struct kref ref;&lt;br /&gt;
    struct mutex lock;&lt;br /&gt;
    mig_state_t mig_state;&lt;br /&gt;
    struct gsp_migration *migration;&lt;br /&gt;
    uint64_t bar1_offset;         // BAR1 aperture offset&lt;br /&gt;
    uint64_t bar1_size;           // BAR1 aperture size&lt;br /&gt;
    uint64_t pt_base;             // Page table base&lt;br /&gt;
    uint64_t pt_size;             // Page table size&lt;br /&gt;
    uint64_t cmd_base;            // Command buffer base&lt;br /&gt;
    uint64_t cmd_size;            // Command buffer size&lt;br /&gt;
    struct gsp_wpr_region *wpr_regions;&lt;br /&gt;
    struct list_head wpr_list;&lt;br /&gt;
    struct gsp_bar_state bar_state;&lt;br /&gt;
    atomic_t refcount;&lt;br /&gt;
    bool active;&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Initialization Sequence ==&lt;br /&gt;
&lt;br /&gt;
=== 1. PCI Probe ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;static int gsp_probe(struct pci_dev *pdev, const struct pci_device_id *id) {&lt;br /&gt;
    struct gsp_device *gsp;&lt;br /&gt;
    int ret;&lt;br /&gt;
    &lt;br /&gt;
    gsp = devm_kzalloc(&amp;amp;amp;pdev-&amp;amp;gt;dev, sizeof(*gsp), GFP_KERNEL);&lt;br /&gt;
    gsp-&amp;amp;gt;pdev = pdev;&lt;br /&gt;
    pci_set_drvdata(pdev, gsp);&lt;br /&gt;
    &lt;br /&gt;
    // Enable PCI device&lt;br /&gt;
    ret = pcim_enable_device(pdev);&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    // Map BARs&lt;br /&gt;
    gsp-&amp;amp;gt;bar0 = pcim_iomap(pdev, 0, 0);&lt;br /&gt;
    gsp-&amp;amp;gt;bar1 = pcim_iomap(pdev, 1, 0);&lt;br /&gt;
    if (!gsp-&amp;amp;gt;bar0 || !gsp-&amp;amp;gt;bar1) return -ENOMEM;&lt;br /&gt;
    &lt;br /&gt;
    // Load firmware&lt;br /&gt;
    ret = gsp_firmware_load(gsp, &amp;quot;gsp-570.144.fwimage.bin&amp;quot;);&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    // Initialize RPC client&lt;br /&gt;
    gsp-&amp;amp;gt;rpc = gsp_rpc_client_init(gsp);&lt;br /&gt;
    if (IS_ERR(gsp-&amp;amp;gt;rpc)) return PTR_ERR(gsp-&amp;amp;gt;rpc);&lt;br /&gt;
    &lt;br /&gt;
    // Setup IRQ/MSI-X&lt;br /&gt;
    ret = gsp_setup_irq(gsp);&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    // Initialize debugfs&lt;br /&gt;
    gsp_debugfs_init(gsp);&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Firmware Loading ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_firmware_load(struct gsp_device *gsp, const char *name) {&lt;br /&gt;
    const struct firmware *fw;&lt;br /&gt;
    int ret;&lt;br /&gt;
    &lt;br /&gt;
    ret = request_firmware(&amp;amp;amp;fw, name, &amp;amp;amp;gsp-&amp;amp;gt;pdev-&amp;amp;gt;dev);&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    // Verify MD5: 13ce12a392a31eeb79a2e6ebd3a4a93a&lt;br /&gt;
    if (!gsp_firmware_verify(fw-&amp;amp;gt;data, fw-&amp;amp;gt;size)) {&lt;br /&gt;
        release_firmware(fw);&lt;br /&gt;
        return -EINVAL;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Load to GSP memory (via BAR1)&lt;br /&gt;
    ret = gsp_firmware_upload(gsp, fw-&amp;amp;gt;data, fw-&amp;amp;gt;size);&lt;br /&gt;
    release_firmware(fw);&lt;br /&gt;
    &lt;br /&gt;
    return ret;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. GSP Boot ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_boot(struct gsp_device *gsp) {&lt;br /&gt;
    // 1. Reset GSP&lt;br /&gt;
    writel(1, gsp-&amp;amp;gt;bar0 + GSP_RESET_REG);&lt;br /&gt;
    msleep(10);&lt;br /&gt;
    writel(0, gsp-&amp;amp;gt;bar0 + GSP_RESET_REG);&lt;br /&gt;
    &lt;br /&gt;
    // 2. Wait for entry point (0x04009000) to signal ready&lt;br /&gt;
    ret = gsp_wait_for_ready(gsp, 5000);  // 5s timeout&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    // 3. Initialize RPC dispatchers&lt;br /&gt;
    ret = gsp_rpc_init_dispatchers(gsp);&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== RPC Client Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== Doorbell Mechanism ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#define GSP_DOORBELL_OFFSET   0x1000&lt;br /&gt;
#define GSP_MSG_RING_SIZE     256&lt;br /&gt;
#define GSP_MSG_MAX_SIZE      256&lt;br /&gt;
&lt;br /&gt;
struct gsp_rpc_client {&lt;br /&gt;
    struct gsp_device *gsp;&lt;br /&gt;
    struct mutex lock;&lt;br /&gt;
    uint32_t seq;&lt;br /&gt;
    wait_queue_head_t wq;&lt;br /&gt;
    struct gsp_msg_ring *ring;&lt;br /&gt;
    struct completion *pending[GSP_MAX_PENDING];&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static int gsp_rpc_send_sync(struct gsp_rpc_client *rpc,&lt;br /&gt;
                             uint32_t rpc_type,&lt;br /&gt;
                             void *payload, size_t payload_size,&lt;br /&gt;
                             void *response, size_t *response_size) {&lt;br /&gt;
    struct gsp_msg msg = {&lt;br /&gt;
        .hdr = {&lt;br /&gt;
            .magic = 0x47535052,&lt;br /&gt;
            .version = 1,&lt;br /&gt;
            .rpc_type = rpc_type,&lt;br /&gt;
            .sequence = atomic_inc_return(&amp;amp;amp;rpc-&amp;amp;gt;seq),&lt;br /&gt;
            .timestamp_ns = ktime_get_ns(),&lt;br /&gt;
            .payload_size = payload_size,&lt;br /&gt;
            .flags = MSG_SYNC,&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    struct completion done;&lt;br /&gt;
    init_completion(&amp;amp;amp;done);&lt;br /&gt;
    &lt;br /&gt;
    mutex_lock(&amp;amp;amp;rpc-&amp;amp;gt;lock);&lt;br /&gt;
    rpc-&amp;amp;gt;pending[msg.hdr.sequence % GSP_MAX_PENDING] = &amp;amp;amp;done;&lt;br /&gt;
    &lt;br /&gt;
    // Copy message to ring buffer&lt;br /&gt;
    memcpy(msg.hdr.payload, payload, payload_size);&lt;br /&gt;
    gsp_ring_write(rpc-&amp;amp;gt;ring, &amp;amp;amp;msg, GSP_MSG_MAX_SIZE);&lt;br /&gt;
    &lt;br /&gt;
    // Ring doorbell&lt;br /&gt;
    writel(1, rpc-&amp;amp;gt;gsp-&amp;amp;gt;bar0 + GSP_DOORBELL_OFFSET);&lt;br /&gt;
    &lt;br /&gt;
    mutex_unlock(&amp;amp;amp;rpc-&amp;amp;gt;lock);&lt;br /&gt;
    &lt;br /&gt;
    // Wait for completion&lt;br /&gt;
    if (!wait_for_completion_timeout(&amp;amp;amp;done, msecs_to_jiffies(5000)))&lt;br /&gt;
        return -ETIMEDOUT;&lt;br /&gt;
    &lt;br /&gt;
    // Copy response&lt;br /&gt;
    if (response &amp;amp;amp;&amp;amp;amp; response_size) {&lt;br /&gt;
        *response_size = min(*response_size, done.payload_size);&lt;br /&gt;
        memcpy(response, done.payload, *response_size);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return done.status;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Completion Handler (ISR) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;static irqreturn_t gsp_isr(int irq, void *data) {&lt;br /&gt;
    struct gsp_device *gsp = data;&lt;br /&gt;
    struct gsp_msg msg;&lt;br /&gt;
    &lt;br /&gt;
    while (gsp_ring_read(gsp-&amp;amp;gt;rpc-&amp;amp;gt;ring, &amp;amp;amp;msg)) {&lt;br /&gt;
        if (msg.hdr.flags &amp;amp;amp; MSG_SYNC) {&lt;br /&gt;
            struct completion *done = &lt;br /&gt;
                gsp-&amp;amp;gt;rpc-&amp;amp;gt;pending[msg.hdr.sequence % GSP_MAX_PENDING];&lt;br /&gt;
            if (done) {&lt;br /&gt;
                done-&amp;amp;gt;status = msg.payload.status;&lt;br /&gt;
                done-&amp;amp;gt;payload_size = msg.hdr.payload_size;&lt;br /&gt;
                memcpy(done-&amp;amp;gt;payload, msg.payload.data, msg.hdr.payload_size);&lt;br /&gt;
                complete(done);&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            // Async notification&lt;br /&gt;
            gsp_handle_notification(gsp, &amp;amp;amp;msg);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return IRQ_HANDLED;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== VF Lifecycle ==&lt;br /&gt;
&lt;br /&gt;
=== Create VF ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_vf_create(struct gsp_device *gsp, uint32_t vf_id,&lt;br /&gt;
                  const struct gsp_vf_config *config) {&lt;br /&gt;
    struct gsp_vf *vf;&lt;br /&gt;
    int ret;&lt;br /&gt;
    &lt;br /&gt;
    mutex_lock(&amp;amp;amp;gsp-&amp;amp;gt;vf_lock);&lt;br /&gt;
    &lt;br /&gt;
    if (idr_alloc(&amp;amp;amp;gsp-&amp;amp;gt;vf_idr, NULL, vf_id, vf_id + 1, GFP_KERNEL) &amp;amp;lt; 0) {&lt;br /&gt;
        ret = -EBUSY;&lt;br /&gt;
        goto unlock;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    vf = kzalloc(sizeof(*vf), GFP_KERNEL);&lt;br /&gt;
    vf-&amp;amp;gt;gsp = gsp;&lt;br /&gt;
    vf-&amp;amp;gt;id = vf_id;&lt;br /&gt;
    kref_init(&amp;amp;amp;vf-&amp;amp;gt;ref);&lt;br /&gt;
    mutex_init(&amp;amp;amp;vf-&amp;amp;gt;lock);&lt;br /&gt;
    INIT_LIST_HEAD(&amp;amp;amp;vf-&amp;amp;gt;wpr_list);&lt;br /&gt;
    &lt;br /&gt;
    // Configure VF resources&lt;br /&gt;
    vf-&amp;amp;gt;bar1_offset = config-&amp;amp;gt;bar1_offset;&lt;br /&gt;
    vf-&amp;amp;gt;bar1_size = config-&amp;amp;gt;bar1_size;&lt;br /&gt;
    vf-&amp;amp;gt;pt_base = config-&amp;amp;gt;pt_base;&lt;br /&gt;
    vf-&amp;amp;gt;pt_size = config-&amp;amp;gt;pt_size;&lt;br /&gt;
    vf-&amp;amp;gt;cmd_base = config-&amp;amp;gt;cmd_base;&lt;br /&gt;
    vf-&amp;amp;gt;cmd_size = config-&amp;amp;gt;cmd_size;&lt;br /&gt;
    &lt;br /&gt;
    // Initialize WPR for VF&lt;br /&gt;
    ret = gsp_vf_wpr_init(vf);&lt;br /&gt;
    if (ret) goto err_wpr;&lt;br /&gt;
    &lt;br /&gt;
    // Initialize BAR for VF&lt;br /&gt;
    ret = gsp_vf_bar_init(vf);&lt;br /&gt;
    if (ret) goto err_bar;&lt;br /&gt;
    &lt;br /&gt;
    list_add(&amp;amp;amp;vf-&amp;amp;gt;list, &amp;amp;amp;gsp-&amp;amp;gt;vf_list);&lt;br /&gt;
    vf-&amp;amp;gt;active = true;&lt;br /&gt;
    &lt;br /&gt;
    mutex_unlock(&amp;amp;amp;gsp-&amp;amp;gt;vf_lock);&lt;br /&gt;
    return 0;&lt;br /&gt;
    &lt;br /&gt;
err_bar:&lt;br /&gt;
    gsp_vf_wpr_fini(vf);&lt;br /&gt;
err_wpr:&lt;br /&gt;
    idr_remove(&amp;amp;amp;gsp-&amp;amp;gt;vf_idr, vf_id);&lt;br /&gt;
    kfree(vf);&lt;br /&gt;
unlock:&lt;br /&gt;
    mutex_unlock(&amp;amp;amp;gsp-&amp;amp;gt;vf_lock);&lt;br /&gt;
    return ret;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Destroy VF ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;void gsp_vf_destroy(struct gsp_vf *vf) {&lt;br /&gt;
    struct gsp_device *gsp = vf-&amp;amp;gt;gsp;&lt;br /&gt;
    uint32_t id = vf-&amp;amp;gt;id;&lt;br /&gt;
    &lt;br /&gt;
    mutex_lock(&amp;amp;amp;gsp-&amp;amp;gt;vf_lock);&lt;br /&gt;
    vf-&amp;amp;gt;active = false;&lt;br /&gt;
    list_del(&amp;amp;amp;vf-&amp;amp;gt;list);&lt;br /&gt;
    mutex_unlock(&amp;amp;amp;gsp-&amp;amp;gt;vf_lock);&lt;br /&gt;
    &lt;br /&gt;
    gsp_vf_bar_fini(vf);&lt;br /&gt;
    gsp_vf_wpr_fini(vf);&lt;br /&gt;
    &lt;br /&gt;
    if (vf-&amp;amp;gt;migration)&lt;br /&gt;
        gsp_migration_cancel(vf-&amp;amp;gt;migration);&lt;br /&gt;
    &lt;br /&gt;
    kref_put(&amp;amp;amp;vf-&amp;amp;gt;ref, gsp_vf_release);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void gsp_vf_release(struct kref *ref) {&lt;br /&gt;
    struct gsp_vf *vf = container_of(ref, struct gsp_vf, ref);&lt;br /&gt;
    kfree(vf);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Memory Management (ALLOC/PIN) ==&lt;br /&gt;
&lt;br /&gt;
=== Allocate VF Memory ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_vf_mem_alloc(struct gsp_vf *vf, &lt;br /&gt;
                     uint64_t size, uint32_t flags,&lt;br /&gt;
                     uint64_t *handle, uint64_t *va) {&lt;br /&gt;
    struct alloc_payload payload = {&lt;br /&gt;
        .size = size,&lt;br /&gt;
        .type = MEM_TYPE_VRAM,&lt;br /&gt;
        .alignment = 0x1000,&lt;br /&gt;
        .va_hint = 0,&lt;br /&gt;
        .flags = flags,&lt;br /&gt;
        .pid = current-&amp;amp;gt;pid,&lt;br /&gt;
        .vf_id = vf-&amp;amp;gt;id,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    struct alloc_response resp;&lt;br /&gt;
    size_t resp_size = sizeof(resp);&lt;br /&gt;
    &lt;br /&gt;
    return gsp_rpc_send_sync(vf-&amp;amp;gt;gsp-&amp;amp;gt;rpc, RPC_ALLOC,&lt;br /&gt;
                             &amp;amp;amp;payload, sizeof(payload),&lt;br /&gt;
                             &amp;amp;amp;resp, &amp;amp;amp;resp_size);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pin Memory for DMA ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_vf_mem_pin(struct gsp_vf *vf, uint64_t handle,&lt;br /&gt;
                   uint64_t offset, uint64_t size,&lt;br /&gt;
                   uint64_t *dma_addr) {&lt;br /&gt;
    struct pin_payload payload = {&lt;br /&gt;
        .handle = handle,&lt;br /&gt;
        .offset = offset,&lt;br /&gt;
        .size = size,&lt;br /&gt;
        .vf_id = vf-&amp;amp;gt;id,&lt;br /&gt;
        .flags = PIN_WRITE | PIN_READ,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    struct pin_response resp;&lt;br /&gt;
    size_t resp_size = sizeof(resp);&lt;br /&gt;
    &lt;br /&gt;
    return gsp_rpc_send_sync(vf-&amp;amp;gt;gsp-&amp;amp;gt;rpc, RPC_PIN,&lt;br /&gt;
                             &amp;amp;amp;payload, sizeof(payload),&lt;br /&gt;
                             &amp;amp;amp;resp, &amp;amp;amp;resp_size);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging &amp;amp;amp; Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Debugfs Interface ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# List VFs&lt;br /&gt;
cat /sys/kernel/debug/gsp/vfs&lt;br /&gt;
&lt;br /&gt;
# VF details&lt;br /&gt;
cat /sys/kernel/debug/gsp/vf/1/status&lt;br /&gt;
&lt;br /&gt;
# RPC statistics&lt;br /&gt;
cat /sys/kernel/debug/gsp/rpc/stats&lt;br /&gt;
&lt;br /&gt;
# BAR state&lt;br /&gt;
cat /sys/kernel/debug/gsp/vf/1/bar&lt;br /&gt;
&lt;br /&gt;
# WPR regions&lt;br /&gt;
cat /sys/kernel/debug/gsp/vf/1/wpr&lt;br /&gt;
&lt;br /&gt;
# Migration status&lt;br /&gt;
cat /sys/kernel/debug/gsp/vf/1/migration&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Trace Events ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# Enable tracing&lt;br /&gt;
echo 1 &amp;amp;gt; /sys/kernel/debug/tracing/events/gsp/enable&lt;br /&gt;
&lt;br /&gt;
# Trace migration&lt;br /&gt;
trace-cmd record -e gsp_mig_phase -e gsp_mig_transfer&lt;br /&gt;
&lt;br /&gt;
# Trace WPR&lt;br /&gt;
trace-cmd record -e gsp_wpr_event&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unit Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// kselftest for gsp-rpc&lt;br /&gt;
static void test_rpc_alloc(void) {&lt;br /&gt;
    struct gsp_vf *vf = create_test_vf();&lt;br /&gt;
    uint64_t handle, va;&lt;br /&gt;
    &lt;br /&gt;
    ASSERT_EQ(gsp_vf_mem_alloc(vf, 4096, 0, &amp;amp;amp;handle, &amp;amp;amp;va), 0);&lt;br /&gt;
    ASSERT_NE(handle, 0);&lt;br /&gt;
    ASSERT_NE(va, 0);&lt;br /&gt;
    &lt;br /&gt;
    gsp_vf_mem_free(vf, handle);&lt;br /&gt;
    destroy_test_vf(vf);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error Handling Checklist ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Scenario&lt;br /&gt;
! Detection&lt;br /&gt;
! Recovery&lt;br /&gt;
|-&lt;br /&gt;
| GSP firmware crash&lt;br /&gt;
| Watchdog timeout&lt;br /&gt;
| Reset GSP, reload FW&lt;br /&gt;
|-&lt;br /&gt;
| RPC timeout&lt;br /&gt;
| Doorbell no response&lt;br /&gt;
| Retry, then VF reset&lt;br /&gt;
|-&lt;br /&gt;
| BAR trap storm&lt;br /&gt;
| Rate limit exceeded&lt;br /&gt;
| Throttle VF&lt;br /&gt;
|-&lt;br /&gt;
| WPR violation&lt;br /&gt;
| Callback storm&lt;br /&gt;
| Quarantine VF&lt;br /&gt;
|-&lt;br /&gt;
| Migration fail&lt;br /&gt;
| Commit verify fail&lt;br /&gt;
| Rollback to source&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Performance Tuning ==&lt;br /&gt;
&lt;br /&gt;
=== RPC Batching ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Batch multiple ALLOCs in single RPC&lt;br /&gt;
struct batch_alloc_payload {&lt;br /&gt;
    uint32_t count;&lt;br /&gt;
    struct alloc_payload allocs[MAX_BATCH];&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Async Completion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Use async RPC for non-critical paths&lt;br /&gt;
gsp_rpc_send_async(rpc, RPC_NOTIFY, payload, size, callback, ctx);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Memory Pool ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Pre-allocate bounce buffers&lt;br /&gt;
struct gsp_bounce_pool {&lt;br /&gt;
    struct page **pages;&lt;br /&gt;
    int count;&lt;br /&gt;
    spinlock_t lock;&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
* GSP Firmware: gsp-570.144.fwimage.bin&lt;br /&gt;
* Base Address: 0x04000000&lt;br /&gt;
* Primary Dispatcher: 0x057A1AC0&lt;br /&gt;
* Secondary Dispatcher: 0x04ED39DC&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=WPR_Management&amp;diff=23992</id>
		<title>WPR Management</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=WPR_Management&amp;diff=23992"/>
		<updated>2026-10-12T04:41:02Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= WPR (Write/Read Protect Region) Management =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' WPR is the '''write-protected region of VRAM reserved for firmware''', not a generic read/write-protect mechanism; the read-protect framing below is historical reverse-engineering material. Canonical documentation: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
WPR (Write Protect Region / Read Protect Region) provides memory isolation for vGPU by protecting guest memory regions from unauthorized access. The GSP firmware implements WPR through two handlers at '''0x04F00B0C''' and '''0x04F00C78''' (62 KB each).&lt;br /&gt;
&lt;br /&gt;
== Key Addresses ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Handler&lt;br /&gt;
! Address&lt;br /&gt;
! Size&lt;br /&gt;
! Role&lt;br /&gt;
|-&lt;br /&gt;
| WPR Handler 1&lt;br /&gt;
| 0x04F00B0C&lt;br /&gt;
| 62 KB&lt;br /&gt;
| Primary WPR management&lt;br /&gt;
|-&lt;br /&gt;
| WPR Handler 2&lt;br /&gt;
| 0x04F00C78&lt;br /&gt;
| 62 KB&lt;br /&gt;
| Secondary/timeout handling&lt;br /&gt;
|-&lt;br /&gt;
| String Table&lt;br /&gt;
| 60 locations&lt;br /&gt;
| —&lt;br /&gt;
| Completion/timeout strings&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== String References (60 Total) ==&lt;br /&gt;
&lt;br /&gt;
=== Completion Events ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;WPR_WRITE_COMPLETE      0x5E478F8&lt;br /&gt;
WPR_READ_COMPLETE       0x5E478E0&lt;br /&gt;
NV_WPR_WRITE_COMPLETE   0x5E478C8&lt;br /&gt;
NV_WPR_READ_COMPLETE    0x5E478B0&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Timeout Events ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;WPR_WRITE_TIMEOUT       0x5E47898&lt;br /&gt;
WPR_READ_TIMEOUT        0x5E47880&lt;br /&gt;
NV_WPR_WRITE_TIMEOUT    0x5E47868&lt;br /&gt;
NV_WPR_READ_TIMEOUT     0x5E47850&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WPR State Machine ==&lt;br /&gt;
&lt;br /&gt;
=== Handler 1: 0x04F00B0C (Primary) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef enum {&lt;br /&gt;
    WPR_STATE_IDLE = 0,&lt;br /&gt;
    WPR_STATE_WRITE_PENDING = 1,&lt;br /&gt;
    WPR_STATE_READ_PENDING = 2,&lt;br /&gt;
    WPR_STATE_COMPLETE = 3,&lt;br /&gt;
    WPR_STATE_TIMEOUT = 4,&lt;br /&gt;
    WPR_STATE_ERROR = 0xFFFF&lt;br /&gt;
} wpr_state_t;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
    uint64_t region_base;      // Protected region base&lt;br /&gt;
    uint64_t region_size;      // Region size (page-aligned)&lt;br /&gt;
    uint32_t vf_id;            // Owning VF&lt;br /&gt;
    uint32_t flags;            // WPR_WRITE | WPR_READ | WPR_EXECUTE&lt;br /&gt;
    wpr_state_t state;&lt;br /&gt;
    uint64_t timeout_ns;       // Operation timeout&lt;br /&gt;
    void *completion_cb;       // Callback on complete&lt;br /&gt;
    void *timeout_cb;          // Callback on timeout&lt;br /&gt;
} wpr_region_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Operation Flow ===&lt;br /&gt;
&lt;br /&gt;
==== Write Protect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;1. VF requests WPR_WRITE on region [base, base+size)&lt;br /&gt;
2. Handler validates alignment (4KB) and permissions&lt;br /&gt;
3. Programs MMU/IOMMU write-protect bits&lt;br /&gt;
4. Starts timeout timer (configurable)&lt;br /&gt;
5. On GPU write attempt:&lt;br /&gt;
   a. Trap to GSP via page fault&lt;br /&gt;
   b. Check if VF owns region&lt;br /&gt;
   c. If allowed: emulate write, return OK&lt;br /&gt;
   d. If denied: trigger WPR_WRITE_COMPLETE/NV_WPR_WRITE_COMPLETE&lt;br /&gt;
6. On timeout: trigger WPR_WRITE_TIMEOUT/NV_WPR_WRITE_TIMEOUT&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Read Protect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;1. VF requests WPR_READ on region&lt;br /&gt;
2. Programs MMU/IOMMU read-protect bits&lt;br /&gt;
3. On GPU read attempt:&lt;br /&gt;
   a. Trap to GSP&lt;br /&gt;
   b. Return zero/poison data or emulate&lt;br /&gt;
   c. Trigger WPR_READ_COMPLETE/NV_WPR_READ_COMPLETE&lt;br /&gt;
4. On timeout: trigger WPR_READ_TIMEOUT/NV_WPR_READ_TIMEOUT&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== VBIOS Parsing (Handler 2: 0x04F00C78) ==&lt;br /&gt;
&lt;br /&gt;
The WPR handlers parse VBIOS structures for legacy compatibility:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int parse_vbios_for_wpr(void *vbios_ptr, size_t size) {&lt;br /&gt;
    // Search for signatures:&lt;br /&gt;
    // 0xAA55 - Standard VBIOS signature&lt;br /&gt;
    // 0x57464F4E (&amp;quot;WFON&amp;quot;) - WPR enable&lt;br /&gt;
    // 0x5746564E (&amp;quot;WFVN&amp;quot;) - WPR version&lt;br /&gt;
    &lt;br /&gt;
    for (offset = 0; offset &amp;amp;lt; size; offset += 0x1000) {&lt;br /&gt;
        uint32_t sig = *(uint32_t*)(vbios_ptr + offset);&lt;br /&gt;
        &lt;br /&gt;
        if (sig == 0xAA55) {&lt;br /&gt;
            // Check for WPR structures&lt;br /&gt;
            parse_wpr_tables(vbios_ptr + offset);&lt;br /&gt;
        }&lt;br /&gt;
        else if (sig == 0x57464F4E || sig == 0x5746564E) {&lt;br /&gt;
            // WPR enabled in VBIOS&lt;br /&gt;
            wpr_vbios_enabled = true;&lt;br /&gt;
            wpr_vbios_offset = offset;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Integration with GSP Subsystems ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Allocator (0x429B450) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Allocate WPR metadata structures&lt;br /&gt;
wpr_region_t *wpr_alloc_region() {&lt;br /&gt;
    return UNK_ram_058A1A9C(0x429B450, sizeof(wpr_region_t));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Allocate bounce buffers for emulation&lt;br /&gt;
void *wpr_alloc_bounce(size_t size) {&lt;br /&gt;
    return UNK_ram_058A1A9C(0x429B450, size);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DMA/Copy Engine (0x0588F9C4, 0x05AEC86C) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Copy data for WPR emulation&lt;br /&gt;
int wpr_emulate_access(wpr_region_t *rgn, void *dst, void *src, size_t size) {&lt;br /&gt;
    return UNK_ram_0588F9C4(dma_engine, src, dst, size);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logging (0x05AB7DA0) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Log WPR events&lt;br /&gt;
void wpr_log_event(const char *event_str, uint32_t vf_id, uint64_t addr) {&lt;br /&gt;
    UNK_ram_05AB7DA0(1, &amp;amp;amp;event_str);  // Log string&lt;br /&gt;
    UNK_ram_05AB7DA0(2, &amp;amp;amp;vf_id);      // Log VF ID&lt;br /&gt;
    UNK_ram_05AB7DA0(3, &amp;amp;amp;addr);       // Log address&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== vGPU-IO Integration ==&lt;br /&gt;
&lt;br /&gt;
=== Kernel WPR API ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct gsp_wpr_ops {&lt;br /&gt;
    int (*protect_write)(struct gsp_device *gsp, &lt;br /&gt;
                         uint32_t vf_id,&lt;br /&gt;
                         uint64_t base, uint64_t size);&lt;br /&gt;
    int (*protect_read)(struct gsp_device *gsp,&lt;br /&gt;
                        uint32_t vf_id,&lt;br /&gt;
                        uint64_t base, uint64_t size);&lt;br /&gt;
    int (*unprotect)(struct gsp_device *gsp,&lt;br /&gt;
                     uint32_t vf_id,&lt;br /&gt;
                     uint64_t base);&lt;br /&gt;
    int (*set_timeout)(struct gsp_device *gsp,&lt;br /&gt;
                       uint32_t vf_id,&lt;br /&gt;
                       uint64_t timeout_ns);&lt;br /&gt;
    int (*register_callback)(struct gsp_device *gsp,&lt;br /&gt;
                             uint32_t vf_id,&lt;br /&gt;
                             enum wpr_event_type type,&lt;br /&gt;
                             void (*cb)(struct wpr_event *));&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static const struct gsp_wpr_ops gsp_wpr_ops = {&lt;br /&gt;
    .protect_write = gsp_wpr_write_protect,&lt;br /&gt;
    .protect_read = gsp_wpr_read_protect,&lt;br /&gt;
    .unprotect = gsp_wpr_unprotect,&lt;br /&gt;
    .set_timeout = gsp_wpr_set_timeout,&lt;br /&gt;
    .register_callback = gsp_wpr_register_callback,&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== VF WPR Lifecycle ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// VF initialization: register WPR regions&lt;br /&gt;
int gsp_vf_wpr_init(struct gsp_vf *vf) {&lt;br /&gt;
    // Protect VF's page tables&lt;br /&gt;
    gsp_wpr_ops.protect_write(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id,&lt;br /&gt;
                              vf-&amp;amp;gt;pt_base, vf-&amp;amp;gt;pt_size);&lt;br /&gt;
    &lt;br /&gt;
    // Protect VF's command buffers&lt;br /&gt;
    gsp_wpr_ops.protect_write(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id,&lt;br /&gt;
                              vf-&amp;amp;gt;cmd_base, vf-&amp;amp;gt;cmd_size);&lt;br /&gt;
    &lt;br /&gt;
    // Set default timeout (10ms)&lt;br /&gt;
    gsp_wpr_ops.set_timeout(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id, 10000000);&lt;br /&gt;
    &lt;br /&gt;
    // Register completion callbacks&lt;br /&gt;
    gsp_wpr_ops.register_callback(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id,&lt;br /&gt;
                                  WPR_EVENT_WRITE_COMPLETE,&lt;br /&gt;
                                  vf_wpr_write_complete_cb);&lt;br /&gt;
    gsp_wpr_ops.register_callback(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id,&lt;br /&gt;
                                  WPR_EVENT_TIMEOUT,&lt;br /&gt;
                                  vf_wpr_timeout_cb);&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// VF cleanup&lt;br /&gt;
void gsp_vf_wpr_fini(struct gsp_vf *vf) {&lt;br /&gt;
    gsp_wpr_ops.unprotect(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id, vf-&amp;amp;gt;pt_base);&lt;br /&gt;
    gsp_wpr_ops.unprotect(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id, vf-&amp;amp;gt;cmd_base);&lt;br /&gt;
    // ... unregister callbacks&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Callback Handling ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;static void vf_wpr_write_complete_cb(struct wpr_event *evt) {&lt;br /&gt;
    struct gsp_vf *vf = evt-&amp;amp;gt;vf;&lt;br /&gt;
    &lt;br /&gt;
    // Log the write attempt&lt;br /&gt;
    dev_dbg(vf-&amp;amp;gt;dev, &amp;quot;WPR write complete: VF=%u addr=0x%llx\n&amp;quot;,&lt;br /&gt;
            vf-&amp;amp;gt;id, evt-&amp;amp;gt;address);&lt;br /&gt;
    &lt;br /&gt;
    // If this was a page table update, invalidate TLB&lt;br /&gt;
    if (evt-&amp;amp;gt;address &amp;amp;gt;= vf-&amp;amp;gt;pt_base &amp;amp;amp;&amp;amp;amp; &lt;br /&gt;
        evt-&amp;amp;gt;address &amp;amp;lt; vf-&amp;amp;gt;pt_base + vf-&amp;amp;gt;pt_size) {&lt;br /&gt;
        gsp_tlb_invalidate(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void vf_wpr_timeout_cb(struct wpr_event *evt) {&lt;br /&gt;
    struct gsp_vf *vf = evt-&amp;amp;gt;vf;&lt;br /&gt;
    &lt;br /&gt;
    dev_warn(vf-&amp;amp;gt;dev, &amp;quot;WPR timeout: VF=%u type=%d addr=0x%llx\n&amp;quot;,&lt;br /&gt;
             vf-&amp;amp;gt;id, evt-&amp;amp;gt;type, evt-&amp;amp;gt;address);&lt;br /&gt;
    &lt;br /&gt;
    // Escalate: reset VF or throttle&lt;br /&gt;
    if (evt-&amp;amp;gt;type == WPR_EVENT_WRITE_TIMEOUT) {&lt;br /&gt;
        gsp_vf_throttle(vf);&lt;br /&gt;
    } else {&lt;br /&gt;
        gsp_vf_reset(vf);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error Codes ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x1E&lt;br /&gt;
| ETIME&lt;br /&gt;
| Operation timed out&lt;br /&gt;
|-&lt;br /&gt;
| 0x1F&lt;br /&gt;
| EDEV&lt;br /&gt;
| Device error&lt;br /&gt;
|-&lt;br /&gt;
| 0x25&lt;br /&gt;
| EOVERFLOW&lt;br /&gt;
| Region too large&lt;br /&gt;
|-&lt;br /&gt;
| 0x37&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Invalid alignment&lt;br /&gt;
|-&lt;br /&gt;
| 0x51&lt;br /&gt;
| ENOMEM&lt;br /&gt;
| Out of memory&lt;br /&gt;
|-&lt;br /&gt;
| 0x56&lt;br /&gt;
| EBUSY&lt;br /&gt;
| Region busy&lt;br /&gt;
|-&lt;br /&gt;
| 0xFFFF&lt;br /&gt;
| EPERM&lt;br /&gt;
| Permission denied&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
&lt;br /&gt;
=== Monitor These Addresses ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;0x04296048  : Global error flag&lt;br /&gt;
0x0429B750+0x111300 : Error status register&lt;br /&gt;
0x05E47850-0x05E478F8 : WPR string table&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GSP Log Patterns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;WPR_WRITE_COMPLETE    VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
WPR_READ_COMPLETE     VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
WPR_WRITE_TIMEOUT     VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
WPR_READ_TIMEOUT      VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
NV_WPR_WRITE_COMPLETE VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
NV_WPR_READ_COMPLETE  VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
NV_WPR_WRITE_TIMEOUT  VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
NV_WPR_READ_TIMEOUT   VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Trace Points ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// In kernel driver&lt;br /&gt;
trace_gsp_wpr_protect(vf_id, base, size, type);&lt;br /&gt;
trace_gsp_wpr_event(vf_id, event_type, address, status);&lt;br /&gt;
trace_gsp_wpr_timeout(vf_id, address, elapsed_ns);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
* Handler 1: &amp;lt;code&amp;gt;FUN_ram_04f00b0c_ram_04f00b0c.c&amp;lt;/code&amp;gt; (62 KB)&lt;br /&gt;
* Handler 2: &amp;lt;code&amp;gt;FUN_ram_04f00c78_ram_04f00c78.c&amp;lt;/code&amp;gt; (62 KB)&lt;br /&gt;
* RPC Types: Handled via primary/secondary dispatchers&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=UVM_in_the_Guest&amp;diff=23991</id>
		<title>UVM in the Guest</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=UVM_in_the_Guest&amp;diff=23991"/>
		<updated>2026-10-12T04:41:02Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= UVM in the Guest =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' What UVM (&amp;lt;code&amp;gt;nvidia_uvm.ko&amp;lt;/code&amp;gt;) does inside the guest, why it is the most demanding consumer of the virtual GPU's semantics, and how it waits. Canonical source: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/04-uvm.md &amp;lt;code&amp;gt;../docs/03-architecture/04-uvm.md&amp;lt;/code&amp;gt;]; where this page and the docs tree disagree, the docs tree wins.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed with the stock guest driver; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partially working, software bridge in charge; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented default-off; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; planned end state.&lt;br /&gt;
&lt;br /&gt;
== 1. What UVM is ==&lt;br /&gt;
&lt;br /&gt;
UVM provides unified memory and GPU-driven page-fault handling. In practice it is a '''second GPU driver layered on the RM''', owning GPU address spaces and running its own memory-management work on the GPU.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Component&lt;br /&gt;
! Role&lt;br /&gt;
|-&lt;br /&gt;
| VA spaces (&amp;lt;code&amp;gt;uvm_va_space&amp;lt;/code&amp;gt;)&lt;br /&gt;
| per-process GPU address spaces&lt;br /&gt;
|-&lt;br /&gt;
| Channel managers&lt;br /&gt;
| pools of GPU channels (CE, SEC2, GR as needed) for UVM's work&lt;br /&gt;
|-&lt;br /&gt;
| Push buffers / GPFIFO&lt;br /&gt;
| UVM builds and submits its own pushes&lt;br /&gt;
|-&lt;br /&gt;
| Semaphores and trackers&lt;br /&gt;
| UVM waits on GPU-written semaphores to track completion&lt;br /&gt;
|-&lt;br /&gt;
| Page trees&lt;br /&gt;
| GPU page tables for its VA spaces&lt;br /&gt;
|-&lt;br /&gt;
| Fault handling&lt;br /&gt;
| fault buffer plus notification; UVM resolves and replays/cancels faults&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For CUDA, UVM is entered early: &amp;lt;code&amp;gt;cuInit&amp;lt;/code&amp;gt; → driver init → &amp;lt;code&amp;gt;UVM_REGISTER_GPU&amp;lt;/code&amp;gt;. If UVM cannot register the GPU, CUDA does not start — which is why &amp;quot;UVM advances&amp;quot; is the project's primary correctness metric on the way to CUDA.&lt;br /&gt;
&lt;br /&gt;
== 2. The registration path (traced end to end) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;libcuda: UVM_REGISTER_GPU ioctl (0x25)&lt;br /&gt;
  uvm_api_register_gpu -&amp;amp;gt; uvm_va_space_register_gpu -&amp;amp;gt; uvm_gpu_retain_by_uuid&lt;br /&gt;
    nvUvmInterfaceRegisterGpu / GetGpuInfo; alloc_parent_gpu / add_gpu&lt;br /&gt;
      nvUvmInterfaceDeviceCreate          (RM object creation)&lt;br /&gt;
      uvm_hal_init_gpu / get_gpu_caps     (CE caps)&lt;br /&gt;
      uvm_ats_add_gpu / uvm_gpu_init_isr  (fault/interrupt plumbing)&lt;br /&gt;
    init_channel_manager&lt;br /&gt;
      create semaphore pool (sysmem)&lt;br /&gt;
      create channels per CE (GPFIFO + pushbuffer + semaphores)&lt;br /&gt;
      channel_init() -&amp;amp;gt; first push -&amp;amp;gt; semaphore release -&amp;amp;gt; wait&lt;br /&gt;
    uvm_page_tree_init                      (page tables for the VA space)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each stage has a distinct failure signature — see [[Guest Driver Lifecycle: A Field Guide|&amp;lt;code&amp;gt;Driver-Lifecycle-Field-Guide.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
== 3. What UVM requires from the &amp;quot;GPU&amp;quot; ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Requirement&lt;br /&gt;
! Detail&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| GPU identity&lt;br /&gt;
| must match the UUID from RM&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| CE capabilities&lt;br /&gt;
| per-engine support bits; UVM requires &amp;lt;code&amp;gt;supported &amp;amp;amp;&amp;amp;amp; !grce &amp;amp;amp;&amp;amp;amp; sysmem&amp;lt;/code&amp;gt; for CPU_TO_GPU / GPU_TO_CPU channels&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; caps accepted; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; copies forwarded to the physical copy engine&lt;br /&gt;
|-&lt;br /&gt;
| Channel creation&lt;br /&gt;
| RM channel objects with GPFIFO/userd/instance parameters&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Pushes executed&lt;br /&gt;
| first action on a new channel is an init push plus a semaphore-tracked wait&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; software bridge executes memsets, copies and releases; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; CE-class copies forwarded&lt;br /&gt;
|-&lt;br /&gt;
| Page trees&lt;br /&gt;
| UVM initializes page trees with its own pushes; server-owned ranges must be populated by us&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Fault delivery&lt;br /&gt;
| fault buffer plus notification; replay/cancel semantics&lt;br /&gt;
| &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; backend-side observation/relay; guest contract &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Completion semantics&lt;br /&gt;
| tracker values must advance exactly&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Current frontier.''' Context creation and the full CUDA driver-API smoke pass (&amp;lt;code&amp;gt;ALL OK&amp;lt;/code&amp;gt;, copies matched) run end to end. CE-class copies are forwarded to the physical copy engine (default off) with engine-authored releases and a fault relay. For GR, a forwarded guest launch reaches the front-end but the inline launch-descriptor install has not been observed; context validity at dispatch is ruled out ([[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]). The remaining UVM work is completion translation and the guest-side fault replay/cancel contract.&lt;br /&gt;
&lt;br /&gt;
== 4. The discovery that defines the work: how UVM waits ==&lt;br /&gt;
&lt;br /&gt;
UVM's tracker is the single most visible symptom of an unfaithful GPU. It spins, and after 30 seconds it dumps its state:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;uvm_tracker.c:285 Tracker entry for value 1 (sema VA 0x121000000)&lt;br /&gt;
uvm_channel.c:4184 pending push '' started at uvm_channel.c:2535 in channel_init()&lt;br /&gt;
    releasing value 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mechanically, UVM built a push ending in a '''semaphore release''' — a method sequence (CE channel class, e.g. &amp;lt;code&amp;gt;TURING_DMA_COPY_A&amp;lt;/code&amp;gt;) that sets an address and a payload and launches a DMA operation to write the payload to memory — then submitted it and waits for the payload to appear. On real hardware the copy engine writes it; on our device nobody does unless the emulation does. The push we found in guest RAM decodes as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;20010000 0000c5b5   set-object (TURING_DMA_COPY_A)&lt;br /&gt;
2001a000 0000c076   set-object (GP100_UVM_SW)&lt;br /&gt;
20038090 00000001   incrementing-method header: count 3, addr 0x240&lt;br /&gt;
21000000 00000001   lower 32 bits of the semaphore VA; payload (1)&lt;br /&gt;
200180c0 0000000c   LAUNCH_DMA with SEMAPHORE_TYPE=RELEASE_ONE_WORD&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So the emulation's job for this push is: '''write &amp;lt;code&amp;gt;payload&amp;lt;/code&amp;gt; to the memory at the semaphore's GPU VA''', which requires a GPU-VA → guest-PA translation. The host does this through the learned VA→PA map: while the channel's GPFIFO has pending entries it reads each push, decodes the method stream and runs the work (page-table memsets, copies, semaphore releases). When a push page cannot be resolved — or a channel consumes entries without any release landing — it falls back to content: guest RAM is scanned for release groups and pending payloads are applied forward-only. A release is applied only when &amp;lt;code&amp;gt;payload &amp;amp;gt; current&amp;lt;/code&amp;gt;, so recycled push buffers and stale copies are harmless. One pitfall observed live: a semaphore-page VA can flap between two physical pages across map rebuilds; pinning the validated translation fixes the stalled wait.&lt;br /&gt;
&lt;br /&gt;
== 5. The memory model UVM assumes ==&lt;br /&gt;
&lt;br /&gt;
* UVM's semaphore pool is '''system memory''' (&amp;lt;code&amp;gt;UVM_APERTURE_SYS&amp;lt;/code&amp;gt;), one 4 KiB page per channel manager, addressed as 4-byte slots (1024 per page).&lt;br /&gt;
* Each page has a '''GPU VA''' (chosen by the client's RM) and a '''CPU VA''' (a kernel mapping). UVM polls the CPU VA; the GPU writes the GPU VA.&lt;br /&gt;
* Both addresses are recorded in UVM's structures in guest memory — the key that makes translation possible without extra help from the guest.&lt;br /&gt;
* The CPU VA is a direct-map address, so &amp;lt;code&amp;gt;PA = cpu_va - page_offset_base&amp;lt;/code&amp;gt; (verified live: writing the payload there completes the push).&lt;br /&gt;
* Values are per channel and monotonic (1, 2, 3 …); UVM's own check (&amp;lt;code&amp;gt;UVM_GPU_SEMAPHORE_MAX_JUMP&amp;lt;/code&amp;gt;) detects and reports wrong values.&lt;br /&gt;
* The client's page tables for '''server-owned ranges are empty chains''': the client hands us the physical addresses of its page-table levels and expects the server to own the lower levels ([[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 6. Page trees and faults ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;uvm_page_tree_init&amp;lt;/code&amp;gt; initializes a VA space's page tables with pushes on UVM's own channels (memops and page-table writes; the copy engine executes them on real hardware). Fault handling is event-driven: UVM programs a fault buffer (replayable and non-replayable; sizes from &amp;lt;code&amp;gt;INTERNAL_GMMU_GET_STATIC_INFO&amp;lt;/code&amp;gt;, answered by the emulation) and, on a fault, reads the entry, populates the page table and replays or cancels the fault with a &amp;lt;code&amp;gt;MEM_OP&amp;lt;/code&amp;gt; push. Reconciling the guest's memory model with the real GPU's here is the deepest remaining work.&lt;br /&gt;
&lt;br /&gt;
== 7. How to observe UVM ==&lt;br /&gt;
&lt;br /&gt;
In the guest, UVM prints nothing by default:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;echo 1 | sudo tee /sys/module/nvidia_uvm/parameters/uvm_debug_prints&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Messages then appear with the &amp;lt;code&amp;gt;nvidia-uvm:&amp;lt;/code&amp;gt; prefix. Known-good markers, in order: &amp;lt;code&amp;gt;uvm_gpu_retain_by_uuid&amp;lt;/code&amp;gt; → channel manager created → &amp;lt;code&amp;gt;uvm_page_tree_init&amp;lt;/code&amp;gt; pushes → &amp;lt;code&amp;gt;UVM_REGISTER_GPU&amp;lt;/code&amp;gt; returns and CUDA proceeds. Failure signatures characterized live:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Message&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Failed to initialize the channel manager: NV_ERR_NOT_SUPPORTED&amp;lt;/code&amp;gt;&lt;br /&gt;
| CE caps wrong or missing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;stuck waiting&amp;lt;/code&amp;gt; plus &amp;lt;code&amp;gt;Tracker entry ... channel_init()&amp;lt;/code&amp;gt;&lt;br /&gt;
| the push's semaphore was never written&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Assert failed ... unexpected semaphore ... jump from 0x0 to 0x1010101&amp;lt;/code&amp;gt;&lt;br /&gt;
| a wrong payload was written; UVM caught it&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 8. Why UVM is the perfect correctness oracle ==&lt;br /&gt;
&lt;br /&gt;
UVM exercises in minutes what a driver test suite would test in hours: memory allocation, page tables, channel setup, push generation, semaphore semantics, fault handling and error recovery — all with continuous self-checks and loud diagnostics. When UVM registers cleanly and CUDA workloads pass, the device is behaving like a real GPU.&lt;br /&gt;
&lt;br /&gt;
== 9. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/04-uvm.md &amp;lt;code&amp;gt;../docs/03-architecture/04-uvm.md&amp;lt;/code&amp;gt;] — canonical chapter (this page's source).&lt;br /&gt;
* [[The Guest Stack and CUDASW|&amp;lt;code&amp;gt;Guest-Stack-and-CUDASW.md&amp;lt;/code&amp;gt;]], [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]] — the guest stack and the RM objects UVM consumes.&lt;br /&gt;
* [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]] — the userspace half of the contract; [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]], [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]] — how UVM's pushes execute, and the current wall.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/04-implementation/01-known-knowns-and-unknowns.md &amp;lt;code&amp;gt;../docs/04-implementation/01-known-knowns-and-unknowns.md&amp;lt;/code&amp;gt;] — server-owned page tables and the fault contract.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=System_Overview&amp;diff=23990</id>
		<title>System Overview</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=System_Overview&amp;diff=23990"/>
		<updated>2026-10-12T04:41:02Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= System Overview =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' The one page to read if you want to understand ''how Open-IOV works'' before diving into any subsystem. Condensed from [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/01-system-overview.md &amp;lt;code&amp;gt;../docs/03-architecture/01-system-overview.md&amp;lt;/code&amp;gt;] (with [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/09-full-system-picture.md &amp;lt;code&amp;gt;../docs/03-architecture/09-full-system-picture.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/10-interaction-and-scheduling.md &amp;lt;code&amp;gt;../docs/03-architecture/10-interaction-and-scheduling.md&amp;lt;/code&amp;gt;] for the full picture); the docs tree wins on disagreement.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; proven with the stock guest driver; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented default-off; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partial; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; current blocker; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; designed end state.&lt;br /&gt;
&lt;br /&gt;
== 1. The core principle ==&lt;br /&gt;
&lt;br /&gt;
'''Emulate the interface. Pass through the work. Never patch anyone.'''&lt;br /&gt;
&lt;br /&gt;
A virtual GPU is a ''mediated passthrough'' device. The guest must believe it owns a real NVIDIA GPU with a real GPU System Processor running firmware; the host must arrange for the guest's work to execute on real hardware, because emulating compute in software is orders of magnitude too slow to be useful.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EMULATE  (software; the guest expects virtual hardware)&lt;br /&gt;
  PCI configuration space, capability structures, power management&lt;br /&gt;
  BAR0 register interface (shadow, not the physical GPU's BAR0)&lt;br /&gt;
  BAR1 VRAM aperture (guest-visible video memory)&lt;br /&gt;
  GSP firmware boot handshake (FWSEC -&amp;amp;gt; booter -&amp;amp;gt; RISCV -&amp;amp;gt; boot complete)&lt;br /&gt;
  GSP-RM message queues, RPC transport, resource-manager controls&lt;br /&gt;
  event/notification channels; MSI-X injection (via eventfd)&lt;br /&gt;
&lt;br /&gt;
PASS THROUGH  (real hardware; correctness and performance)&lt;br /&gt;
  GPU memory: guest VRAM objects backed by real VRAM       [target]&lt;br /&gt;
  page tables / GMMU state used by the GPU                 [wip]&lt;br /&gt;
  channel execution: guest push buffers on real channels   [gated/wall]&lt;br /&gt;
  compute (CUDA) and, later, 3D/video work                 [wip/planned]&lt;br /&gt;
  DMA, completion and fault interrupts relayed to the guest&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The line between the two is the '''interface boundary''', and it moves as the project matures: early work emulates everything the guest can observe; later work forwards everything that must be fast.&lt;br /&gt;
&lt;br /&gt;
== 2. Layer map ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GUEST&lt;br /&gt;
  application ── CUDA runtime (libcudart) ─┐&lt;br /&gt;
  application ── CUDA driver  (libcuda)   ─┤  userspace: CUDASW stack&lt;br /&gt;
  OpenGL/Vulkan ── libGLX/libvulkan ──────┘&lt;br /&gt;
        │  ioctls / mmaps&lt;br /&gt;
  nvidia.ko (unmodified)  ── RM core, resource server, UVM, modeset/drm&lt;br /&gt;
        │  MMIO + DMA + MSI-X   (a virtual PCIe device)&lt;br /&gt;
════════╪════════════════════════════════════════════════════════&lt;br /&gt;
HYPERVISOR (KVM/QEMU, later Xen/...)  VFIO mdev transport + IOMMU&lt;br /&gt;
        │&lt;br /&gt;
HOST MODULE  vgsp.ko&lt;br /&gt;
  ├─ virtual device: config space, BAR0/BAR1/BAR3 windows, MSI-X&lt;br /&gt;
  ├─ emulation core: GSP boot + GSP-RM (RPC msgq, controls, objects, events)&lt;br /&gt;
  ├─ memory model: guest RAM access, VA&amp;amp;lt;-&amp;amp;gt;PA maps, VRAM backing&lt;br /&gt;
  └─ work path: channel/push forwarding to the physical GPU&lt;br /&gt;
        │ module-owned device + real GSP session&lt;br /&gt;
HOST BACKEND  the GPU's own hardware + GSP firmware, driven by this module&lt;br /&gt;
        │     (the distribution nvidia.ko stays unmodified and unbound in&lt;br /&gt;
        │      this mode)&lt;br /&gt;
        v&lt;br /&gt;
REAL HARDWARE (engines, memory, interrupts)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The guest never contains Open-IOV code; the host driver is unmodified; the hypervisor is unmodified. The only new component is &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. How each side works ==&lt;br /&gt;
&lt;br /&gt;
* '''Guest side.''' The stock driver performs the GSP boot handshake, sets up RPC message queues in guest memory, creates RM objects, programs channels and submits work — exactly as on bare metal ([[The Guest Stack and CUDASW|&amp;lt;code&amp;gt;Guest-Stack-and-CUDASW.md&amp;lt;/code&amp;gt;]], [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]], [[UVM in the Guest|&amp;lt;code&amp;gt;UVM-in-the-Guest.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
* '''Host module.''' &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt; is a VFIO mediated-device driver: it registers a parent on the physical GPU, exposes virtual GPU types, and each mdev is one virtual GPU for one VM. Inside, it presents a plausible Turing-class device (config space, BAR shadows, MSI-X), answers the GSP boot handshake and the RPC protocol with well-formed replies, and maintains the memory model that resolves guest physical addresses to host addresses ([[The Host Module (vgsp.ko)|&amp;lt;code&amp;gt;Host-Module.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
* '''The interface that makes this possible.''' Since Turing, the driver's management path is not ''silicon'', it is ''firmware'': the GSP runs a version of NVIDIA's Resource Manager and the driver talks to it over shared-memory queues with a small RPC protocol. That protocol is small, stable and observable — so the project emulates '''the firmware's interface''' instead of emulating a GPU ([[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]], [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/03-gsp-and-gsp-rm.md &amp;lt;code&amp;gt;../docs/03-architecture/03-gsp-and-gsp-rm.md&amp;lt;/code&amp;gt;]).&lt;br /&gt;
* '''Execution.''' Guest work that must be fast (copies, kernels) is forwarded to a real pipeline driven through the module's own GSP-RM session ([[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]], [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]], [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 4. Data flows ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;MMIO from the guest:&lt;br /&gt;
  guest nvidia.ko writes BAR0 offset X&lt;br /&gt;
    -&amp;amp;gt; KVM exit -&amp;amp;gt; QEMU -&amp;amp;gt; VFIO region write into the mdev&lt;br /&gt;
    -&amp;amp;gt; BAR0 shadow state machine (doorbells, VF registers, notify)&lt;br /&gt;
    -&amp;amp;gt; may wake the emulation thread&lt;br /&gt;
&lt;br /&gt;
RPC from the guest to &amp;quot;firmware&amp;quot;:&lt;br /&gt;
  guest writes a command-queue element into a guest-memory msgq&lt;br /&gt;
    -&amp;amp;gt; doorbell (BAR0)&lt;br /&gt;
    -&amp;amp;gt; emulation thread reads the queue through the hypervisor's guest-RAM&lt;br /&gt;
       accessor, parses the element, dispatches the RPC&lt;br /&gt;
    -&amp;amp;gt; handler produces a reply element in the status queue&lt;br /&gt;
    -&amp;amp;gt; emulation injects an MSI-X interrupt to the guest&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. What runs today ==&lt;br /&gt;
&lt;br /&gt;
# Guest boots, enumerates the virtual PCIe device, binds &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt;.&lt;br /&gt;
# The GSP boot handshake completes against the emulation.&lt;br /&gt;
# Message queues are set up, versions negotiated, RM initialization exchanges complete; object creation, capability queries, vaspaces, channels and the engine inventory are answered with well-formed replies (a small set of control IDs is special-cased with real values; reply fidelity for consumed fields keeps improving).&lt;br /&gt;
# &amp;lt;code&amp;gt;nvidia-smi -L&amp;lt;/code&amp;gt; enumerates the device; CUDA userspace starts; context creation completes; the full driver-API smoke passes (&amp;lt;code&amp;gt;ALL OK&amp;lt;/code&amp;gt;, 64-byte payload round-trips).&lt;br /&gt;
# CE-class copies are forwarded to the physical copy engine (default off) with engine-authored semaphore releases and a fault relay. For GR (graphics/compute), a forwarded guest launch reaches the front-end but the engine has not executed it yet — the current frontier ([[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 6. Where the detail lives ==&lt;br /&gt;
&lt;br /&gt;
* [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]] — the firmware/RM architecture and the transport we emulate.&lt;br /&gt;
* [[The Host Module (vgsp.ko)|&amp;lt;code&amp;gt;Host-Module.md&amp;lt;/code&amp;gt;]] — the module's internals.&lt;br /&gt;
* [[The Guest Stack and CUDASW|&amp;lt;code&amp;gt;Guest-Stack-and-CUDASW.md&amp;lt;/code&amp;gt;]], [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]] — the guest side.&lt;br /&gt;
* [[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]], [[UVM in the Guest|&amp;lt;code&amp;gt;UVM-in-the-Guest.md&amp;lt;/code&amp;gt;]] — memory and translation.&lt;br /&gt;
* [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]], [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]], [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]] — work and execution.&lt;br /&gt;
* [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]] — supported combinations and portability.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/01-system-overview.md &amp;lt;code&amp;gt;../docs/03-architecture/01-system-overview.md&amp;lt;/code&amp;gt;] and the rest of the architecture corpus in the repository.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Risc-v-gsp-rm-debugger&amp;diff=23989</id>
		<title>Risc-v-gsp-rm-debugger</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Risc-v-gsp-rm-debugger&amp;diff=23989"/>
		<updated>2026-10-12T04:41:01Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= risc-v-gsp-rm-debugger =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' risc-v-gsp-rm-debugger runs GSP/uproc firmware off-hardware in a controllable RISC-V machine, instruments it with Frida-like primitives, and records durable sessions so firmware behaviour can be captured and compared with evidence instead of anecdotes. Canonical sources: [https://git.vgpu.io/open-iov.git/tree/docs/05-operations/03-risc-v-gsp-rm-vm.md &amp;lt;code&amp;gt;../docs/05-operations/03-risc-v-gsp-rm-vm.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov.git/tree/docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md &amp;lt;code&amp;gt;../docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md&amp;lt;/code&amp;gt;]; if this page and the docs tree disagree, the docs tree wins.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Development-only.''' Host-side tooling that is never shipped, never a driver dependency and never present in a guest; interfaces and file formats may change without notice.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; recorded QEMU sessions; &amp;lt;code&amp;gt;[design]&amp;lt;/code&amp;gt; device model and custom simulator are roadmap.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. What it is ==&lt;br /&gt;
&lt;br /&gt;
risc-v-gsp-rm-debugger makes the firmware's '''runtime behaviour''' inspectable. It boots GSP/uproc firmware in &amp;lt;code&amp;gt;qemu-system-riscv64&amp;lt;/code&amp;gt; (or a deterministic native interpreter) and offers Frida-like primitives on top:&lt;br /&gt;
&lt;br /&gt;
* breakpoints and enter/leave hooks (RV64 ABI aware); watchpoints on firmware variables;&lt;br /&gt;
* memory read/write/hexdump/search, structure decoding, snapshot diffing;&lt;br /&gt;
* recorded sessions: a replayable event stream plus memory dumps;&lt;br /&gt;
* remote calls and run-to-cursor (execute until a chosen address);&lt;br /&gt;
* injection: build a position-independent RV64 service, load it into the running firmware and dispatch to it;&lt;br /&gt;
* declarative probe specs, a plugin API, and a Ghidra bridge for symbol export, hit annotation and decompiler-driven execution.&lt;br /&gt;
&lt;br /&gt;
Its purpose is '''capturing how the firmware server behaves, repeatably and safely''', so emulation changes can be measured against recorded evidence and can survive GSP version, device and architecture churn. The tooling lives under &amp;lt;code&amp;gt;open-iov/debug/risc-v-gsp-rm-vm/&amp;lt;/code&amp;gt;, with its own documentation set (design, usage, scripting, plugins, bridges, accuracy, portability, roadmap).&lt;br /&gt;
&lt;br /&gt;
== 2. What it is not ==&lt;br /&gt;
&lt;br /&gt;
* '''Not a GSP boot environment.''' QEMU &amp;lt;code&amp;gt;virt&amp;lt;/code&amp;gt; has no falcon windows, WPR2, CSB/TRANSCOM, PMU, timers or FB DMA. &amp;lt;code&amp;gt;probe&amp;lt;/code&amp;gt; reports exactly where the real image first diverges (for the TU104 570.144 image: a load-access fault at firmware vaddr &amp;lt;code&amp;gt;0x4009014&amp;lt;/code&amp;gt; reading &amp;lt;code&amp;gt;0x2000000000000A00&amp;lt;/code&amp;gt;) — expected data, not a boot. A device model is a roadmap item, not a claim.&lt;br /&gt;
* '''Not a timing model.''' Do not infer latency, jitter or concurrency behaviour from it; its in-scope conclusions are execution flow and memory side effects.&lt;br /&gt;
* '''Not a replacement for Ghidra or the guest diagnostics.''' Ghidra answers ''what is the code''; risc-v-gsp-rm-debugger answers ''what did it do''; the guest driver remains the oracle for guest-side behaviour.&lt;br /&gt;
* '''Not a hardware or security tool.''' It never attaches to a real GPU, a guest, a kernel module or an mdev, and it is never a security or confidentiality boundary.&lt;br /&gt;
&lt;br /&gt;
== 3. Where it fits ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Layer&lt;br /&gt;
! Tool&lt;br /&gt;
! Question answered&lt;br /&gt;
|-&lt;br /&gt;
| Static&lt;br /&gt;
| Ghidra and the decompilation corpus&lt;br /&gt;
| what is the code?&lt;br /&gt;
|-&lt;br /&gt;
| Guest driver&lt;br /&gt;
| guest diagnostics, ptrace tracing&lt;br /&gt;
| what did the driver request?&lt;br /&gt;
|-&lt;br /&gt;
| '''Firmware runtime'''&lt;br /&gt;
| '''risc-v-gsp-rm-debugger'''&lt;br /&gt;
| '''what does the firmware server do, repeatably and safely?'''&lt;br /&gt;
|-&lt;br /&gt;
| Physical backend&lt;br /&gt;
| supervised hardware sessions, module logs&lt;br /&gt;
| what did real silicon / the real GSP-RM do?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The intended measurement loop: capture the real backend's RPC behaviour, run the same stimulus in risc-v-gsp-rm-debugger, and compare the recorded sessions with the tool's accuracy metrics. A simulator observation is evidence about the firmware, not about silicon; anything that would change the product is reproduced on a physical reference first.&lt;br /&gt;
&lt;br /&gt;
== 4. Quickstart ==&lt;br /&gt;
&lt;br /&gt;
Requirements: Linux, Python 3.10+ (standard library only), &amp;lt;code&amp;gt;qemu-system-riscv64&amp;lt;/code&amp;gt; (Ubuntu package &amp;lt;code&amp;gt;qemu-system-misc&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;clang&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;lld&amp;lt;/code&amp;gt;. No GPU, no driver and no kernel module are touched. From the repository root:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;cd debug/risc-v-gsp-rm-vm&lt;br /&gt;
./risc-v-gsp-rm-debugger.sh info     # environment check: QEMU, toolchain, paths&lt;br /&gt;
make demo &amp;amp;amp;&amp;amp;amp; make sdk                # build the bundled RV64 uproc demo and the injection SDK&lt;br /&gt;
./risc-v-gsp-rm-debugger.sh demo     # canned run: boot, hooks, watchpoints, session&lt;br /&gt;
./risc-v-gsp-rm-debugger.sh analyze dumps/&amp;amp;lt;printed-session-dir&amp;amp;gt;&lt;br /&gt;
./risc-v-gsp-rm-debugger.sh probe    # real GSP image: report the first divergence&lt;br /&gt;
./risc-v-gsp-rm-debugger.sh inject   # load and invoke a position-independent service&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What &amp;quot;good&amp;quot; looks like: &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; reports QEMU and the demo paths; &amp;lt;code&amp;gt;demo&amp;lt;/code&amp;gt; prints hook/branch lines and a session directory under &amp;lt;code&amp;gt;dumps/&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;analyze&amp;lt;/code&amp;gt; renders hook/watch/breakpoint events and a coherent summary; &amp;lt;code&amp;gt;probe&amp;lt;/code&amp;gt; reports a bounded first divergence (expected data, not a boot); &amp;lt;code&amp;gt;inject&amp;lt;/code&amp;gt; returns matching values on the direct and firmware-dispatched invocation paths.&lt;br /&gt;
&lt;br /&gt;
A large test suite (hundreds of tests) is run with &amp;lt;code&amp;gt;make test&amp;lt;/code&amp;gt;, covering unit tests plus live-QEMU smoke runs.&lt;br /&gt;
&lt;br /&gt;
== 5. The primitives ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Primitive&lt;br /&gt;
! Use it for&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;breakpoint&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;hook&amp;lt;/code&amp;gt;&lt;br /&gt;
| did this function run? with what arguments and return value?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;watch&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;w&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;)&lt;br /&gt;
| when did this field change, and from which store PC?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;run_until&amp;lt;/code&amp;gt;&lt;br /&gt;
| bounded observation; stop at a chosen address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt;&lt;br /&gt;
| remote call to unit-test a function in isolation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;note&amp;lt;/code&amp;gt;&lt;br /&gt;
| single-step with dispatch; annotate the event stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Memory.read/write/hexdump/search/snapshot/diff&amp;lt;/code&amp;gt;&lt;br /&gt;
| inspect and diff memory regions&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SymbolDB&amp;lt;/code&amp;gt;&lt;br /&gt;
| resolve file/program/runtime addresses across sources&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Recorder&amp;lt;/code&amp;gt;&lt;br /&gt;
| write the durable session (events, snapshots, blobs)&lt;br /&gt;
|-&lt;br /&gt;
| injection SDK&lt;br /&gt;
| load, register and invoke your own position-independent RV64 service&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Instructions between stops are invisible unless a trace is on (a TCG plugin on QEMU, or &amp;lt;code&amp;gt;--trace&amp;lt;/code&amp;gt; on the native backend). Two backends — QEMU-RSP and the native interpreter — satisfy the same session API, so scripts, probes, plugins, recordings and comparisons survive a backend change.&lt;br /&gt;
&lt;br /&gt;
== 6. Fidelity levels (what a result can mean) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Level&lt;br /&gt;
! Property&lt;br /&gt;
! risc-v-gsp-rm-debugger today&lt;br /&gt;
|-&lt;br /&gt;
| '''L0'''&lt;br /&gt;
| instruction semantics&lt;br /&gt;
| high (QEMU TCG, same ISA family)&lt;br /&gt;
|-&lt;br /&gt;
| '''L1'''&lt;br /&gt;
| memory behaviour&lt;br /&gt;
| high for RAM-resident code, conditional on mapping&lt;br /&gt;
|-&lt;br /&gt;
| '''L2'''&lt;br /&gt;
| time / concurrency&lt;br /&gt;
| '''not modelled''' — never claim&lt;br /&gt;
|-&lt;br /&gt;
| '''L3'''&lt;br /&gt;
| device environment (falcon, WPR2, CSB, PMU, timers, DMA, IRQ)&lt;br /&gt;
| '''absent''' — device model is roadmap&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A simulator observation is evidence about the firmware, not about silicon. Never quote a session for timing, interrupt, security or confidentiality claims; zero hits in a run are a coverage fact, not proof that code is dead.&lt;br /&gt;
&lt;br /&gt;
== 7. Sessions as evidence ==&lt;br /&gt;
&lt;br /&gt;
Every run records a session directory (format &amp;lt;code&amp;gt;greeneye-session/1&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dumps/&amp;amp;lt;stamp&amp;amp;gt;-&amp;amp;lt;uuid&amp;amp;gt;-&amp;amp;lt;name&amp;amp;gt;/&lt;br /&gt;
  session.json        format, name, counts, snapshot inventory, meta&lt;br /&gt;
  events.jsonl        append-only event stream (hooks, watches, memory, notes)&lt;br /&gt;
  snapshots/*.bin.z   zlib-compressed region captures with sha256&lt;br /&gt;
  blobs/*             QEMU logs, instruction/access traces, extra captures&lt;br /&gt;
  summary.md          rendered analysis&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules that make a session usable as evidence:&lt;br /&gt;
&lt;br /&gt;
# '''Record with a fixed stimulus.''' The same script, seed, budgets and image hash make runs comparable; a self-comparison must be empty.&lt;br /&gt;
# '''Annotate as you go.''' Explain inside the session what was asked and what was changed; a chat log is not evidence.&lt;br /&gt;
# '''Attach the provenance.''' Firmware SHA-256, version string, symbol DB source/hash/bias, and the exact command or script.&lt;br /&gt;
# '''Keep the directory together.''' &amp;lt;code&amp;gt;session.json&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;events.jsonl&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;snapshots/&amp;lt;/code&amp;gt; + blobs are one artifact; a copied event stream alone is not evidence.&lt;br /&gt;
# '''State the fidelity.''' Say which of L0/L1 was exercised and name the reference capture; do not silently waive L2/L3 gaps.&lt;br /&gt;
# '''Report deltas honestly.''' Every remaining delta between two runs is explained or listed as open; an empty unexplained-delta list is a claim that must be earned.&lt;br /&gt;
# '''Prefer an A/B pair.''' Static reading is a hypothesis; a recorded session is evidence; at least two comparable runs are a conclusion.&lt;br /&gt;
&lt;br /&gt;
== 8. Safety and status ==&lt;br /&gt;
&lt;br /&gt;
* '''Simulator only.''' The tools launch their own QEMU or native machine against the bundled demo or an explicitly allowed re-hosted ELF; they never attach to hardware, a guest, a kernel module, an mdev or an existing debugger stub.&lt;br /&gt;
* '''No guest, no hardware, no product.''' Nothing runs in a guest; injected services are prototypes, not shipped code; product changes go through the host module and a supervised physical confirmation.&lt;br /&gt;
* '''Bounded everywhere.''' Runs have durations and stop caps; reads and snapshots have size caps; a wedged target is left stopped and restarted clean rather than poked.&lt;br /&gt;
* '''Local only.''' The Ghidra bridge is a localhost transport, unauthenticated by design; never expose it on a network interface.&lt;br /&gt;
* '''No confidentiality claims.''' The tool is a study environment; never use injection to defeat a hardware security boundary.&lt;br /&gt;
* '''Status.''' The audited v0.1 surfaces are the CLI and the session format. Working and live-verified: hooks/watchpoints, memory tools, sessions, declarative probes, plugins, remote calls, run-to-cursor, the injection SDK, the Ghidra bridges, the first-fault probe and the instruction/access trace. The device model, the custom simulator and serving full host message traffic remain roadmap; porting and packaging scaffolds are pilot-status. Treat interface changes as reviewed events.&lt;br /&gt;
&lt;br /&gt;
== 9. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/05-operations/03-risc-v-gsp-rm-vm.md &amp;lt;code&amp;gt;../docs/05-operations/03-risc-v-gsp-rm-vm.md&amp;lt;/code&amp;gt;] — project-level purpose, status and limits.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md &amp;lt;code&amp;gt;../docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md&amp;lt;/code&amp;gt;] — the single user front door.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/05-operations/02-debugging-and-maintenance-workflows.md &amp;lt;code&amp;gt;../docs/05-operations/02-debugging-and-maintenance-workflows.md&amp;lt;/code&amp;gt;] — captures, failure taxonomy and upgrade workflows.&lt;br /&gt;
* [[GSP 570.144W Firmware Analysis|&amp;lt;code&amp;gt;GSP-570.144W-Firmware-Analysis.md&amp;lt;/code&amp;gt;]] and [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]] — the firmware image and architecture the sessions exercise.&lt;br /&gt;
* [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]] and [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]] — the client side of the RPC traffic and the supervised backend the simulator complements.&lt;br /&gt;
* [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] and [https://git.vgpu.io/open-iov.git/tree/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;] — honest overall status and the documentation front door.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Glossary&amp;diff=23988</id>
		<title>Glossary</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Glossary&amp;diff=23988"/>
		<updated>2026-10-12T04:41:01Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Glossary =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' The terms used across this wiki, the project's documents and its logs. Condensed from [https://git.vgpu.io/open-iov.git/tree/docs/09-reference/glossary-and-faq.md &amp;lt;code&amp;gt;../docs/09-reference/glossary-and-faq.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement. For questions, see [[FAQ|&amp;lt;code&amp;gt;FAQ.md&amp;lt;/code&amp;gt;]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== GPU, driver and virtualization ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Term&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| '''BAR0 / BAR1 / BAR3'''&lt;br /&gt;
| PCI BAR windows of the GPU: register interface (16 MB), VRAM aperture (256 MB), instance/PRAMIN window.&lt;br /&gt;
|-&lt;br /&gt;
| '''CUDASW'''&lt;br /&gt;
| The family of NVIDIA user-space software between applications and the driver: &amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;libcudart&amp;lt;/code&amp;gt;, the JIT compiler, the fatbinary loader, and friends.&lt;br /&gt;
|-&lt;br /&gt;
| '''Doorbell'''&lt;br /&gt;
| A register or memory location a driver writes to signal &amp;quot;new work is available&amp;quot; for a channel or queue.&lt;br /&gt;
|-&lt;br /&gt;
| '''mdev'''&lt;br /&gt;
| Mediated device: the kernel mechanism that turns a physical device into virtual instances (VFIO).&lt;br /&gt;
|-&lt;br /&gt;
| '''vGPU'''&lt;br /&gt;
| Virtual GPU: the device this project presents to a guest.&lt;br /&gt;
|-&lt;br /&gt;
| '''SRIOV / VF'''&lt;br /&gt;
| Single-root I/O virtualization / virtual functions (hardware partitioning).&lt;br /&gt;
|-&lt;br /&gt;
| '''IOMMU / SMMU'''&lt;br /&gt;
| Platform DMA translation and isolation (Intel VT-d / AMD-Vi / ARM SMMU).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== GSP, firmware and the RM ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Term&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| '''GSP'''&lt;br /&gt;
| GPU System Processor: the embedded RISC-V (RV64IMAC) that runs firmware containing the Resource Manager.&lt;br /&gt;
|-&lt;br /&gt;
| '''GSP-RM'''&lt;br /&gt;
| The Resource Manager running on the GSP (the &amp;quot;self-hosted RM&amp;quot;).&lt;br /&gt;
|-&lt;br /&gt;
| '''RM / RM API'''&lt;br /&gt;
| NVIDIA's Resource Manager and the API used to allocate objects and issue controls.&lt;br /&gt;
|-&lt;br /&gt;
| '''RMCore'''&lt;br /&gt;
| The RM's object system: classes, handles, parents, methods.&lt;br /&gt;
|-&lt;br /&gt;
| '''resserv / resource server'''&lt;br /&gt;
| The RM component that owns allocation authority, privileges and lifetimes.&lt;br /&gt;
|-&lt;br /&gt;
| '''FWSEC'''&lt;br /&gt;
| Firmware security processor stage of the GSP boot sequence.&lt;br /&gt;
|-&lt;br /&gt;
| '''WPR'''&lt;br /&gt;
| Write-Protected Region: the VRAM area reserved for firmware.&lt;br /&gt;
|-&lt;br /&gt;
| '''MSGQ'''&lt;br /&gt;
| The GSP message-queue transport: shared-memory element rings with a page table, plus doorbells.&lt;br /&gt;
|-&lt;br /&gt;
| '''VGX version'''&lt;br /&gt;
| The version the guest announces during RPC negotiation; it selects message layouts.&lt;br /&gt;
|-&lt;br /&gt;
| '''Reply fidelity'''&lt;br /&gt;
| How completely an emulated reply matches what real hardware returns, as a ladder: status-only → coherent zeroed params → coherent values for consumed fields → exact values.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Execution engines and memory ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Term&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| '''CE'''&lt;br /&gt;
| Copy Engine: a DMA engine; also used for UVM's internal work.&lt;br /&gt;
|-&lt;br /&gt;
| '''GR'''&lt;br /&gt;
| The graphics/compute engine that executes shaders (graphics pipelines and CUDA kernels).&lt;br /&gt;
|-&lt;br /&gt;
| '''SEC2'''&lt;br /&gt;
| Secure copy engine used by UVM for protected operations.&lt;br /&gt;
|-&lt;br /&gt;
| '''GPFIFO'''&lt;br /&gt;
| GPU FIFO: a ring of entries, each pointing to a push buffer for a channel.&lt;br /&gt;
|-&lt;br /&gt;
| '''Push buffer'''&lt;br /&gt;
| A stream of method calls (engine commands) submitted via a GPFIFO.&lt;br /&gt;
|-&lt;br /&gt;
| '''PBDMA'''&lt;br /&gt;
| The push-buffer DMA engine in the host scheduler that fetches and executes push buffers.&lt;br /&gt;
|-&lt;br /&gt;
| '''QMD'''&lt;br /&gt;
| Queue Meta Data: the per-launch descriptor a GR channel reads to execute a kernel grid.&lt;br /&gt;
|-&lt;br /&gt;
| '''USERD'''&lt;br /&gt;
| Per-channel control block in VRAM: PUT/GET pointers and control state.&lt;br /&gt;
|-&lt;br /&gt;
| '''Runlist'''&lt;br /&gt;
| The scheduler's list of channels eligible to run.&lt;br /&gt;
|-&lt;br /&gt;
| '''TSG'''&lt;br /&gt;
| Time-Slice Group: channels sharing a scheduling slot.&lt;br /&gt;
|-&lt;br /&gt;
| '''Engine record / engine list'''&lt;br /&gt;
| The per-engine descriptors (kind, instance, class, client type) the driver walks after &amp;lt;code&amp;gt;GPU_GET_ENGINES&amp;lt;/code&amp;gt;; each must be self-consistent or the driver rewrites the following allocation.&lt;br /&gt;
|-&lt;br /&gt;
| '''GMMU'''&lt;br /&gt;
| GPU Memory Management Unit: page tables, TLB, fault handling.&lt;br /&gt;
|-&lt;br /&gt;
| '''PDB'''&lt;br /&gt;
| Page Directory Base: root of a GPU page table.&lt;br /&gt;
|-&lt;br /&gt;
| '''PDE / PTE'''&lt;br /&gt;
| Page-directory entry / page-table entry.&lt;br /&gt;
|-&lt;br /&gt;
| '''UVM'''&lt;br /&gt;
| NVIDIA's unified memory module: VA spaces, page trees, faults, channel manager ([[UVM in the Guest|&amp;lt;code&amp;gt;UVM-in-the-Guest.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
|-&lt;br /&gt;
| '''VA / PA / GPA / IOVA'''&lt;br /&gt;
| Virtual address / physical address / guest physical address / I/O virtual address.&lt;br /&gt;
|-&lt;br /&gt;
| '''vidmem / sysmem / aperture'''&lt;br /&gt;
| GPU local memory / system memory / how an address is qualified.&lt;br /&gt;
|-&lt;br /&gt;
| '''Semaphore / tracker'''&lt;br /&gt;
| A memory location written by the GPU to signal progress; UVM's tracker waits on it.&lt;br /&gt;
|-&lt;br /&gt;
| '''AMAPlib'''&lt;br /&gt;
| NVIDIA's shared &amp;quot;address mapping&amp;quot; library: swizzling, bank/channel mapping, aperture rules.&lt;br /&gt;
|-&lt;br /&gt;
| '''HAL'''&lt;br /&gt;
| Hardware abstraction layer: per-generation functions that program registers and formats.&lt;br /&gt;
|-&lt;br /&gt;
| '''Class list (classDB)'''&lt;br /&gt;
| The RM classes reported as supported; engine queries are filtered against it, so the class list, engine list and capability controls must agree.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Method and tooling ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Term&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| '''Host oracle / A-B harness'''&lt;br /&gt;
| The same query or deterministic workload run against a bare-metal host driver and inside the guest, then diffed — the reference for what the guest should have seen.&lt;br /&gt;
|-&lt;br /&gt;
| '''File virtual address (&amp;lt;code&amp;gt;libcuda+0x...&amp;lt;/code&amp;gt;)'''&lt;br /&gt;
| An address relative to the start of a shared object file, as distinct from a runtime mapping or a disassembler program address.&lt;br /&gt;
|-&lt;br /&gt;
| '''Session (risc-v-gsp-rm-debugger)'''&lt;br /&gt;
| A recorded run of the firmware workbench — the unit of evidence ([[risc-v-gsp-rm-debugger|&amp;lt;code&amp;gt;Riscv-GSP-RM-Debugger.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Related pages ==&lt;br /&gt;
&lt;br /&gt;
* [[FAQ|&amp;lt;code&amp;gt;FAQ.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]]&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=RPC_Message_Format&amp;diff=23987</id>
		<title>RPC Message Format</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=RPC_Message_Format&amp;diff=23987"/>
		<updated>2026-10-12T04:41:00Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= GSP RPC Message Format Specification =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' This page describes the legacy BAR0 mailbox RPC model: the 64-byte &amp;lt;code&amp;gt;GSPR&amp;lt;/code&amp;gt; magic header and the 12-type model below are '''not''' the path the guest driver uses. The live GSP-RM path is a message queue in guest system memory with 4 KB queue elements and a 32-byte RPC header (signature &amp;lt;code&amp;gt;0x43505256&amp;lt;/code&amp;gt;, header version &amp;lt;code&amp;gt;0x03000000&amp;lt;/code&amp;gt;); functions are a flat enum (&amp;lt;code&amp;gt;SET_GUEST_SYSTEM_INFO&amp;lt;/code&amp;gt; 1, &amp;lt;code&amp;gt;FREE&amp;lt;/code&amp;gt; 10, &amp;lt;code&amp;gt;GET_GSP_STATIC_INFO&amp;lt;/code&amp;gt; 65, &amp;lt;code&amp;gt;GSP_RM_CONTROL&amp;lt;/code&amp;gt; 76, &amp;lt;code&amp;gt;GSP_RM_ALLOC&amp;lt;/code&amp;gt; 103, ...). Canonical documentation: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/03-gsp-and-gsp-rm.md &amp;lt;code&amp;gt;../docs/03-architecture/03-gsp-and-gsp-rm.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The GSP firmware uses a dispatcher-based RPC system with two dispatchers:&lt;br /&gt;
&lt;br /&gt;
* '''Primary''' (0x057A1AC0): ALLOC, FREE, MAP, UNMAP, PIN, UNPIN, SCHEDULE, YIELD, NOTIFY, BAR_TRAP, MIGRATE, DEBUG&lt;br /&gt;
* '''Secondary''' (0x04ED39DC): Branch-based dispatch for all 11 types&lt;br /&gt;
&lt;br /&gt;
== Primary Dispatcher Call Convention ==&lt;br /&gt;
&lt;br /&gt;
=== Entry Point ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FUN_ram_057a1ac0(&lt;br /&gt;
    uint32_t rpc_type,      // param_1: RPC type (0x01-0x0C)&lt;br /&gt;
    uint8_t  flags_a,       // param_2&lt;br /&gt;
    uint8_t  flags_b,       // param_3&lt;br /&gt;
    uint8_t  flags_c,       // param_4&lt;br /&gt;
    uint32_t *out_subcmd_id,// param_5: Returns sub-command ID&lt;br /&gt;
    uint8_t  *out_a,        // param_6: Echoes flags_b&lt;br /&gt;
    uint8_t  *out_b,        // param_7: Echoes flags_a&lt;br /&gt;
    uint8_t  *out_c         // param_8: Echoes flags_c&lt;br /&gt;
) -&amp;amp;gt; int64_t&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RPC Type to Sub-Command Mapping ===&lt;br /&gt;
&lt;br /&gt;
The primary dispatcher validates RPC type, then indexes into the 32-entry jump table at '''0x057A3AD8'''.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! RPC Type&lt;br /&gt;
! Name&lt;br /&gt;
! Subcmd Range&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x01&lt;br /&gt;
| ALLOC&lt;br /&gt;
| 0-31&lt;br /&gt;
| Uses 0x057E94EC main&lt;br /&gt;
|-&lt;br /&gt;
| 0x02&lt;br /&gt;
| FREE&lt;br /&gt;
| 0-31&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 0x03&lt;br /&gt;
| MAP&lt;br /&gt;
| —&lt;br /&gt;
| Uses secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x04&lt;br /&gt;
| UNMAP&lt;br /&gt;
| 0-31&lt;br /&gt;
| Primary + secondary&lt;br /&gt;
|-&lt;br /&gt;
| 0x05&lt;br /&gt;
| PIN&lt;br /&gt;
| —&lt;br /&gt;
| Uses secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x06&lt;br /&gt;
| UNPIN&lt;br /&gt;
| —&lt;br /&gt;
| Uses secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x07&lt;br /&gt;
| SCHEDULE&lt;br /&gt;
| 0-31&lt;br /&gt;
| Uses 0x051EFBF4 main&lt;br /&gt;
|-&lt;br /&gt;
| 0x08&lt;br /&gt;
| YIELD&lt;br /&gt;
| —&lt;br /&gt;
| Uses secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x09&lt;br /&gt;
| NOTIFY&lt;br /&gt;
| —&lt;br /&gt;
| Uses secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x0A&lt;br /&gt;
| BAR_TRAP&lt;br /&gt;
| —&lt;br /&gt;
| Uses 0x04CB8188&lt;br /&gt;
|-&lt;br /&gt;
| 0x0B&lt;br /&gt;
| MIGRATE&lt;br /&gt;
| 0-15 x2&lt;br /&gt;
| Dual jump tables&lt;br /&gt;
|-&lt;br /&gt;
| 0x0C&lt;br /&gt;
| DEBUG&lt;br /&gt;
| —&lt;br /&gt;
| Unimplemented&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sub-Command Descriptor (Returned by Jump Table Handlers) ===&lt;br /&gt;
&lt;br /&gt;
Each sub-command handler at the jump table returns:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t subcmd_id;     // Constant ID (e.g., 0x10, 0x14, 0x40)&lt;br /&gt;
    uint8_t  echo_flags_b;  // Copy of input flags_b&lt;br /&gt;
    uint8_t  echo_flags_a;  // Copy of input flags_a&lt;br /&gt;
    uint8_t  echo_flags_c;  // Copy of input flags_c&lt;br /&gt;
} __attribute__((packed)) subcmd_descriptor_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Example: Subcmd 3 (0x057A1BCC)'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Returns ID = 0x10&lt;br /&gt;
*out_subcmd_id = 0x10;&lt;br /&gt;
*out_a = flags_b;&lt;br /&gt;
*out_b = flags_a;&lt;br /&gt;
*out_c = flags_c;&lt;br /&gt;
return 0;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Example: Subcmd 0 (0x057A1DB4)'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Returns ID = 0x40&lt;br /&gt;
*out_subcmd_id = 0x40;&lt;br /&gt;
*out_a = flags_b;&lt;br /&gt;
*out_b = flags_a;&lt;br /&gt;
*out_c = flags_c;&lt;br /&gt;
return 0;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Secondary Dispatcher Call Convention ==&lt;br /&gt;
&lt;br /&gt;
=== Entry Point ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FUN_ram_04ed39dc(rpc_message_t *msg) -&amp;amp;gt; int64_t&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message Structure (Inferred) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t rpc_type;      // 0x01-0x0B&lt;br /&gt;
    uint32_t sub_type;      // Sub-operation code&lt;br /&gt;
    uint64_t payload_ptr;   // Pointer to RPC-specific payload&lt;br /&gt;
    uint32_t payload_size;  // Size of payload&lt;br /&gt;
    uint32_t flags;         // Control flags&lt;br /&gt;
    uint64_t context;       // Opaque context&lt;br /&gt;
    uint32_t sequence;      // Sequence number&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} __attribute__((packed)) rpc_message_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Branch-Based Dispatch ===&lt;br /&gt;
&lt;br /&gt;
Secondary dispatcher uses &amp;lt;code&amp;gt;bgeu&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;bltu&amp;lt;/code&amp;gt; branches on &amp;lt;code&amp;gt;rpc_type&amp;lt;/code&amp;gt; register:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# Pseudocode&lt;br /&gt;
if (rpc_type &amp;amp;gt;= 0x0C) goto error;&lt;br /&gt;
switch(rpc_type):&lt;br /&gt;
  case 0x03: call MAP_handler_A;&lt;br /&gt;
  case 0x04: call UNMAP_handler_A;&lt;br /&gt;
  case 0x05: call PIN_handler_A (0x04ED34B8);&lt;br /&gt;
  case 0x06: call UNPIN_handler_A;&lt;br /&gt;
  case 0x07: call SCHEDULE_handler_A;&lt;br /&gt;
  case 0x08: call YIELD_handler_A;&lt;br /&gt;
  case 0x09: call NOTIFY_handler_A;&lt;br /&gt;
  case 0x0A: call BAR_TRAP_handler (0x057675B7);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== RPC-Specific Payloads ==&lt;br /&gt;
&lt;br /&gt;
=== ALLOC (0x01) - Via 0x057E94EC ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint64_t size;          // Allocation size in bytes&lt;br /&gt;
    uint32_t type;          // Memory type (VRAM, sysmem, etc.)&lt;br /&gt;
    uint32_t alignment;     // Alignment requirement&lt;br /&gt;
    uint64_t va_hint;       // Virtual address hint&lt;br /&gt;
    uint32_t flags;         // CACHE_COHERENT, UNCACHED, etc.&lt;br /&gt;
    uint32_t pid;           // Process ID&lt;br /&gt;
    uint32_t vf_id;         // VF ID (for vGPU)&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
    uint64_t *out_handle;   // Output: allocation handle&lt;br /&gt;
    uint64_t *out_va;       // Output: mapped virtual address&lt;br /&gt;
    uint64_t *out_pa;       // Output: physical address&lt;br /&gt;
} alloc_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MAP (0x03) - Handlers 0x05766AB7 / 0x05778A37 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint64_t handle;        // Allocation handle from ALLOC&lt;br /&gt;
    uint64_t va;            // Target virtual address&lt;br /&gt;
    uint64_t size;          // Map size&lt;br /&gt;
    uint32_t prot;          // PROT_READ|PROT_WRITE|PROT_EXEC&lt;br /&gt;
    uint32_t flags;         // MAP_FIXED, MAP_SHARED, etc.&lt;br /&gt;
    uint32_t vf_id;         // Target VF&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} map_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== PIN (0x05) - Handler 0x04ED34B8 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint64_t handle;        // Allocation handle&lt;br /&gt;
    uint64_t offset;        // Offset within allocation&lt;br /&gt;
    uint64_t size;          // Size to pin&lt;br /&gt;
    uint32_t vf_id;         // Target VF&lt;br /&gt;
    uint32_t flags;         // PIN_WRITE, PIN_READ, PIN_LONGTERM&lt;br /&gt;
    uint64_t *out_dma_addr; // Output: DMA address for device&lt;br /&gt;
} pin_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SCHEDULE (0x07) - Via 0x051EFBF4 / 0x05767F37 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t vf_id;         // VF to schedule&lt;br /&gt;
    uint32_t priority;      // Scheduling priority&lt;br /&gt;
    uint64_t time_slice_ns; // Time slice in nanoseconds&lt;br /&gt;
    uint32_t flags;         // PREEMPTIBLE, REALTIME, etc.&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} schedule_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== BAR_TRAP (0x0A) - Handler 0x04CB8188 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t bar_index;     // BAR number (0-5)&lt;br /&gt;
    uint32_t trap_type;     // READ, WRITE, ATOMIC&lt;br /&gt;
    uint64_t offset;        // Offset within BAR&lt;br /&gt;
    uint64_t value;         // Value for writes&lt;br /&gt;
    uint32_t size;          // Access size (1,2,4,8)&lt;br /&gt;
    uint32_t vf_id;         // Trapping VF&lt;br /&gt;
    uint64_t *out_value;    // Output: read value&lt;br /&gt;
} bar_trap_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MIGRATE (0x0B) - Dual Jump Tables ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t phase;         // 0=prepare, 1=transfer, 2=commit, 3=cleanup&lt;br /&gt;
    uint32_t subcmd;        // Sub-command index (0-15 for each table)&lt;br /&gt;
    uint64_t src_vf;        // Source VF&lt;br /&gt;
    uint64_t dst_vf;        // Destination VF&lt;br /&gt;
    uint64_t data_ptr;      // Migration data buffer&lt;br /&gt;
    uint64_t data_size;     // Buffer size&lt;br /&gt;
    uint32_t flags;         // LIVE, POSTCOPY, etc.&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} migrate_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wire Format (Host → GSP) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Legacy BAR0 mailbox format — not used by the guest driver.''' The current msgq header/element facts are in the note at the top of this page.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message Header (64 bytes) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t magic;         // 0x47535052 (&amp;quot;GSPR&amp;quot;)&lt;br /&gt;
    uint32_t version;       // Protocol version (1)&lt;br /&gt;
    uint32_t rpc_type;      // 0x01-0x0C&lt;br /&gt;
    uint32_t sequence;      // Monotonic sequence&lt;br /&gt;
    uint64_t timestamp_ns;  // Submission timestamp&lt;br /&gt;
    uint32_t payload_size;  // Size of payload&lt;br /&gt;
    uint32_t flags;         // MSG_SYNC, MSG_ASYNC, MSG_NOREPLY&lt;br /&gt;
    uint64_t correlation_id;// For async matching&lt;br /&gt;
    uint64_t reserved[3];   // Padding to 64 bytes&lt;br /&gt;
} __attribute__((packed)) rpc_header_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Complete Message ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;+------------------+&lt;br /&gt;
| rpc_header_t     |  64 bytes&lt;br /&gt;
+------------------+&lt;br /&gt;
| payload (varies) |  payload_size bytes&lt;br /&gt;
+------------------+&lt;br /&gt;
| padding to 256B  |  (alignment)&lt;br /&gt;
+------------------+&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Response Format ==&lt;br /&gt;
&lt;br /&gt;
=== Synchronous Response ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    int64_t status;         // 0 = success, negative = error&lt;br /&gt;
    uint32_t rpc_type;      // Echo of request&lt;br /&gt;
    uint32_t sequence;      // Echo of request&lt;br /&gt;
    uint64_t timestamp_ns;  // Completion timestamp&lt;br /&gt;
    uint32_t payload_size;  // Response payload size&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} __attribute__((packed)) rpc_response_header_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error Codes ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| OK&lt;br /&gt;
| Success&lt;br /&gt;
|-&lt;br /&gt;
| -1 (0xFFFF)&lt;br /&gt;
| EPERM&lt;br /&gt;
| Permission denied&lt;br /&gt;
|-&lt;br /&gt;
| -2 (0xFFFE)&lt;br /&gt;
| ENOENT&lt;br /&gt;
| Not found&lt;br /&gt;
|-&lt;br /&gt;
| -3 (0xFFFD)&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Invalid argument&lt;br /&gt;
|-&lt;br /&gt;
| -6 (0xFFFA)&lt;br /&gt;
| ENODEV&lt;br /&gt;
| No such device&lt;br /&gt;
|-&lt;br /&gt;
| -12 (0xFFF4)&lt;br /&gt;
| ENOMEM&lt;br /&gt;
| Out of memory&lt;br /&gt;
|-&lt;br /&gt;
| -16 (0xFFEE)&lt;br /&gt;
| EBUSY&lt;br /&gt;
| Resource busy&lt;br /&gt;
|-&lt;br /&gt;
| -22 (0xFFEA)&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Invalid argument&lt;br /&gt;
|-&lt;br /&gt;
| -28 (0xFFE4)&lt;br /&gt;
| ENOSPC&lt;br /&gt;
| No space left&lt;br /&gt;
|-&lt;br /&gt;
| -37 (0xFFDB)&lt;br /&gt;
| ENOLCK&lt;br /&gt;
| No locks available&lt;br /&gt;
|-&lt;br /&gt;
| -56 (0xFFC8)&lt;br /&gt;
| EBADMSG&lt;br /&gt;
| Bad message&lt;br /&gt;
|-&lt;br /&gt;
| -84 (0xFFAC)&lt;br /&gt;
| EOVERFLOW&lt;br /&gt;
| Value too large&lt;br /&gt;
|-&lt;br /&gt;
| -90 (0xFFA6)&lt;br /&gt;
| ENOSTR&lt;br /&gt;
| Not a stream&lt;br /&gt;
|-&lt;br /&gt;
| -91 (0xFFA5)&lt;br /&gt;
| ENODATA&lt;br /&gt;
| No data available&lt;br /&gt;
|-&lt;br /&gt;
| -94 (0xFFA2)&lt;br /&gt;
| ENOSR&lt;br /&gt;
| Out of streams resources&lt;br /&gt;
|-&lt;br /&gt;
| -97 (0xFF9F)&lt;br /&gt;
| EPROTO&lt;br /&gt;
| Protocol error&lt;br /&gt;
|-&lt;br /&gt;
| -111 (0xFF91)&lt;br /&gt;
| ETIMEDOUT&lt;br /&gt;
| Connection timed out&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Kernel Client Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== Message Builder ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;static int gsp_rpc_send(gsp_client_t *client, uint32_t rpc_type, &lt;br /&gt;
                        void *payload, size_t payload_size,&lt;br /&gt;
                        void *response, size_t *response_size) {&lt;br /&gt;
    rpc_header_t hdr = {&lt;br /&gt;
        .magic = 0x47535052,&lt;br /&gt;
        .version = 1,&lt;br /&gt;
        .rpc_type = rpc_type,&lt;br /&gt;
        .sequence = atomic_inc(&amp;amp;amp;client-&amp;amp;gt;seq),&lt;br /&gt;
        .timestamp_ns = ktime_get_ns(),&lt;br /&gt;
        .payload_size = payload_size,&lt;br /&gt;
        .flags = MSG_SYNC,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    // Build complete message&lt;br /&gt;
    uint8_t msg[256];&lt;br /&gt;
    memcpy(msg, &amp;amp;amp;hdr, sizeof(hdr));&lt;br /&gt;
    memcpy(msg + 64, payload, payload_size);&lt;br /&gt;
    &lt;br /&gt;
    // Submit to GSP doorbell&lt;br /&gt;
    return gsp_doorbell_ring(client-&amp;amp;gt;gsp, msg, sizeof(msg));&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Doorbell Mechanism ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// GSP doorbell register (PCIe BAR0 + offset)&lt;br /&gt;
#define GSP_DOORBELL_OFFSET  0x1000&lt;br /&gt;
&lt;br /&gt;
static void gsp_doorbell_ring(gsp_device_t *gsp, void *msg, size_t len) {&lt;br /&gt;
    // Copy message to shared memory ring&lt;br /&gt;
    // Ring GSP doorbell&lt;br /&gt;
    writel(1, gsp-&amp;amp;gt;bar0 + GSP_DOORBELL_OFFSET);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Async Completion ==&lt;br /&gt;
&lt;br /&gt;
=== Notification Mechanism ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t rpc_type;&lt;br /&gt;
    uint32_t sequence;&lt;br /&gt;
    int64_t status;&lt;br /&gt;
    uint64_t timestamp_ns;&lt;br /&gt;
    uint32_t payload_size;&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} async_completion_t;&lt;br /&gt;
&lt;br /&gt;
// Delivered via MSI-X or GSP notification queue&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
* Primary Dispatcher: 0x057A1AC0&lt;br /&gt;
* Secondary Dispatcher: 0x04ED39DC&lt;br /&gt;
* Jump Table: 0x057A3AD8 (32 entries)&lt;br /&gt;
* RPC Type Jump Table: 0x059BFEB0 (12 types)&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Project_Status&amp;diff=23986</id>
		<title>Project Status</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Project_Status&amp;diff=23986"/>
		<updated>2026-10-12T04:41:00Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Project Status =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' The honest, dated state of the project: what works today, what is in progress, and what is not started. It is refreshed periodically and each claim maps to a maintained document in the repository. Canonical sources: [https://git.vgpu.io/open-iov.git/tree/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;] (project front door), [https://git.vgpu.io/open-iov.git/tree/docs/04-implementation/01-known-knowns-and-unknowns.md &amp;lt;code&amp;gt;../docs/04-implementation/01-known-knowns-and-unknowns.md&amp;lt;/code&amp;gt;] (known-knowns and known-unknowns) and [https://git.vgpu.io/open-iov.git/tree/docs/04-implementation/03-execution-frontier.md &amp;lt;code&amp;gt;../docs/04-implementation/03-execution-frontier.md&amp;lt;/code&amp;gt;] (the execution frontier). When this page and the docs disagree, the docs tree wins.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; proven with the stock guest driver; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented, default-off or behind supervised gates; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partially implemented; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; current blocker; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; named success state; &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; designed, not built.&lt;br /&gt;
&lt;br /&gt;
== 1. Milestone ladder ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Milestone&lt;br /&gt;
! State&lt;br /&gt;
|-&lt;br /&gt;
| Emulated vGPU device (PCI, BARs, MSI-X, VFIO mdev)&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; working&lt;br /&gt;
|-&lt;br /&gt;
| GSP boot emulation (FWSEC / booter / RISCV handshake)&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; working&lt;br /&gt;
|-&lt;br /&gt;
| GSP-RM message queues and RPC transport&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; working&lt;br /&gt;
|-&lt;br /&gt;
| Stock guest driver probe and &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; (TU104)&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; working&lt;br /&gt;
|-&lt;br /&gt;
| CUDA userspace init and the driver-API smoke (&amp;lt;code&amp;gt;cuInit&amp;lt;/code&amp;gt;, device enumeration, &amp;lt;code&amp;gt;cuCtxCreate&amp;lt;/code&amp;gt;, allocation, copies, free, destroy)&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; working — the smoke prints &amp;lt;code&amp;gt;ALL OK&amp;lt;/code&amp;gt; and the 64-byte payload round-trips exactly&lt;br /&gt;
|-&lt;br /&gt;
| Guest CUDA kernel execution on real hardware&lt;br /&gt;
| &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; a forwarded guest launch reaches the engine queue (the front end deposits the methods and the scheduling path accepts them), but the engine does not yet execute the forwarded launch descriptor — an engine-authored release has not been observed. Emulation-mode kernel runs (executed through the host bridge on a no-claim path) have completed green; reproducibility of the green path across boots is an open issue&lt;br /&gt;
|-&lt;br /&gt;
| Physical backend on real hardware (module-owned GPU running its real GSP-RM)&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; boot, RPC session, object creation and copy-engine work proven; GR execution is the same frontier as above&lt;br /&gt;
|-&lt;br /&gt;
| Multi-tenant isolation (mdev per VM, per-context page directories)&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; designed; the baseline service-state ownership work is in progress&lt;br /&gt;
|-&lt;br /&gt;
| OpenGL / Vulkan (3D), video&lt;br /&gt;
| &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Windows guests&lt;br /&gt;
| &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; (target)&lt;br /&gt;
|-&lt;br /&gt;
| Xen / Argo / OpenXT / Qubes Air transports&lt;br /&gt;
| &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; (the emulation core is hypervisor-independent by construction)&lt;br /&gt;
|-&lt;br /&gt;
| Live migration&lt;br /&gt;
| &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Performance numbers&lt;br /&gt;
| &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; — no published numbers yet; any claim will ship with its measurement methodology&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 2. What &amp;quot;CUDA works&amp;quot; means here ==&lt;br /&gt;
&lt;br /&gt;
A green &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; or even a passing driver-API smoke is not &amp;quot;CUDA works&amp;quot;. The project's definition of done for CUDA requires all of the following ([https://git.vgpu.io/open-iov.git/tree/docs/04-implementation/01-known-knowns-and-unknowns.md &amp;lt;code&amp;gt;../docs/04-implementation/01-known-knowns-and-unknowns.md&amp;lt;/code&amp;gt;]):&lt;br /&gt;
&lt;br /&gt;
# Stock guest driver probe, &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt;, device enumeration — done.&lt;br /&gt;
# Context creation and the full driver-API surface (&amp;lt;code&amp;gt;cuMemAlloc&amp;lt;/code&amp;gt;, copies, free, destroy) — done.&lt;br /&gt;
# A guest kernel launch that '''executes on real hardware''' and is proven by an engine-authored completion — the current frontier.&lt;br /&gt;
# Memory the guest's work refers to resolving correctly end to end (the VA↔PA model) — partially, for the paths exercised so far.&lt;br /&gt;
# Correct completion, semaphore and fault semantics back to the guest — CE class work has the relay; GR is open.&lt;br /&gt;
# Reproducibility: every boot, not a lucky one — an open issue.&lt;br /&gt;
# No ad-hoc default-off parameters required for the canonical path.&lt;br /&gt;
&lt;br /&gt;
Until every gate holds, the honest formulation is: '''initialization and the driver-API path work; engine execution is in progress.'''&lt;br /&gt;
&lt;br /&gt;
== 3. How to see it yourself ==&lt;br /&gt;
&lt;br /&gt;
The reference setup takes about half an hour from a fresh host ([[Install and First Run|&amp;lt;code&amp;gt;Install-and-First-Run.md&amp;lt;/code&amp;gt;]]); the current expected outcome is exactly the ladder above — driver probe, &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt;, the full driver-API smoke, and the execution frontier where it stands. The risc-v-gsp-rm-debugger workbench ([[risc-v-gsp-rm-debugger|&amp;lt;code&amp;gt;Riscv-GSP-RM-Debugger.md&amp;lt;/code&amp;gt;]]) is the host-side tooling used to study the firmware side of that frontier.&lt;br /&gt;
&lt;br /&gt;
== 4. How this page is maintained ==&lt;br /&gt;
&lt;br /&gt;
Every claim above carries a date and a tag, maps to a maintained document in the repository, and is refreshed as milestones land. The execution story, with its evidence and its open theories, is on [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
== 5. Related pages ==&lt;br /&gt;
&lt;br /&gt;
* [[Install and First Run|&amp;lt;code&amp;gt;Install-and-First-Run.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]] — which hardware and software combinations are Reference, Target or Experimental.&lt;br /&gt;
* [[FAQ|&amp;lt;code&amp;gt;FAQ.md&amp;lt;/code&amp;gt;]]&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Physical_GPU_Backend_and_Guest_Wiring&amp;diff=23985</id>
		<title>Physical GPU Backend and Guest Wiring</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Physical_GPU_Backend_and_Guest_Wiring&amp;diff=23985"/>
		<updated>2026-10-12T04:40:59Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Physical GPU Backend and Guest Wiring =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' The design that executes guest work on the real GPU: why the host driver cannot be the path and how the live GSP-RM session is wired to the guest-facing emulation. Canonical sources: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/08-physical-gpu-integration.md &amp;lt;code&amp;gt;../docs/03-architecture/08-physical-gpu-integration.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/11-physical-backend-guest-wiring.md &amp;lt;code&amp;gt;../docs/03-architecture/11-physical-backend-guest-wiring.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; proven with the stock guest driver; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented default-off; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partially built; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; current blocker; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; planned end state.&lt;br /&gt;
&lt;br /&gt;
== 1. The problem and its constraints ==&lt;br /&gt;
&lt;br /&gt;
The guest's real work (copies, memory operations, grid launches) must execute on the physical GPU. The constraints: one DKMS kernel module on the host, no daemon and no new host userspace; host and guest drivers unmodified, with no paravirtual enlightenment in the guest; all emulation and translation logic inside the module; and real execution — compute is not emulated in software.&lt;br /&gt;
&lt;br /&gt;
== 2. Why the host driver is not the path ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Interface&lt;br /&gt;
! What it offers&lt;br /&gt;
! Reachable from our module?&lt;br /&gt;
|-&lt;br /&gt;
| Host driver (distribution build)&lt;br /&gt;
| resource management, scheduling, memory&lt;br /&gt;
| No — no general RM entry points for third-party modules, no kernel-client interface, user-pointer ioctl surface&lt;br /&gt;
|-&lt;br /&gt;
| Host driver peer-memory exports&lt;br /&gt;
| pin/map memory for peer devices&lt;br /&gt;
| Partially — memory only, no submission&lt;br /&gt;
|-&lt;br /&gt;
| Vendor vGPU host stack&lt;br /&gt;
| mediated work submission and scheduling&lt;br /&gt;
| Requires the licensed vGPU host branch and a vGPU-aware guest — excluded&lt;br /&gt;
|-&lt;br /&gt;
| SR-IOV virtual functions&lt;br /&gt;
| hardware-partitioned device&lt;br /&gt;
| Not available on this GPU generation&lt;br /&gt;
|-&lt;br /&gt;
| The GPU's own GSP firmware&lt;br /&gt;
| the resource manager server itself&lt;br /&gt;
| Yes — once the module owns the device; this is the path used&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
With an unmodified host driver there is no callable submission interface into it, so the module must own the device and talk to the hardware itself.&lt;br /&gt;
&lt;br /&gt;
== 3. Mechanism options and the decision ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; (A) Proxy through the host driver: module -&amp;amp;gt; host driver's RM -&amp;amp;gt; real channel&lt;br /&gt;
     -&amp;amp;gt; GPU. Needs a modified host driver or a vendor interface — not implementable.&lt;br /&gt;
 (B) Own the GPU; own scheduling (no GSP): module -&amp;amp;gt; own channels/runlists/page&lt;br /&gt;
     tables -&amp;amp;gt; GPU. Reproduces the scheduler, MMU ownership, context switching.&lt;br /&gt;
 (C) Hybrid — only meaningful once (A) and (B) exist; not on the critical path.&lt;br /&gt;
 (D) Own the GPU; use its real GSP firmware as the server      &amp;amp;lt;- chosen&lt;br /&gt;
     guest push -&amp;amp;gt; module -&amp;amp;gt; real GSP-RM session -&amp;amp;gt; real channel -&amp;amp;gt; GPU&lt;br /&gt;
     The module becomes the host-side resource-manager client; scheduling,&lt;br /&gt;
     page tables and context management stay the firmware's job.&lt;br /&gt;
 (E) Vendor-managed sharing (vGPU host stack, SR-IOV VFs) — deployment-gated; out of scope.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Option (D) is the recorded decision (2026-09-29): the only option satisfying module-only, no-daemon, unmodified drivers, real execution, and multi-tenant sharing.&lt;br /&gt;
&lt;br /&gt;
== 4. The chosen mechanism: bring-up ladder ==&lt;br /&gt;
&lt;br /&gt;
The module binds the physical GPU as its driver while the distribution driver is unbound (dedicated-GPU deployment, §9). Each stage is reversible and independently verified:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership''' — the board's power domain is held active across the window (the platform, not PCI, owns it); the module binds the device and maps BAR0/1/3. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Firmware staging''' — the matching GSP image is fetched and validated (ELF64 RISC-V; loadable section, version, hardware signature); no device state touched. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Boot''' — protected region in video memory, secure-verification stage, booter, RISC-V core start: FWSEC → Booter Load → RISC-V active → GSP-RM init-done. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Host RM client''' — the module speaks the already-mapped RPC protocol to the real firmware: device/subdevice, vaspaces, channels, memory. &amp;quot;Call the host driver's RM&amp;quot; becomes &amp;quot;be the RM client&amp;quot;. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Guest mediation''' — the guest-facing emulation stays unchanged; real-resource objects translate to GSP-RM requests, and server-owned ranges populate the real MMU. &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Work path''' — decoded guest pushes become real push streams; resolved host pages map through module-built scratch page tables; the firmware schedules the work. &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Completion relay''' — hardware-completed semaphores land in guest-polled memory; events and faults relay through the existing MSI-X injection path. &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. The two planes and the wiring ==&lt;br /&gt;
&lt;br /&gt;
The '''emulation plane''' serves the guest: BAR shadows, the sysmem msgq protocol, a hand-built TU104 static-configuration model, and a software work pipeline that executes decoded memsets, copies and semaphore releases. The '''physical backend plane''' owns the device, boots the real GSP-RM and runs the RM client ladder. The wiring joins them at the lifecycle seam (mdev create/remove), a static-config identity overlay, a read-only control whitelist, and — for eligible copy-engine work — the scratch-mapped forwarding path, all default-off and fail-open to software.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GUEST (QEMU)    HOST: vgsp.ko (module-owned GPU)                  PHYSICAL GPU&lt;br /&gt;
-----------------------------------------------------------------------------&lt;br /&gt;
INIT  preflight: distribution driver green; no vgsp/mdev/QEMU          [live]&lt;br /&gt;
      claim: power domain held -&amp;amp;gt; distribution driver released -&amp;amp;gt; module&lt;br /&gt;
         binds the device -&amp;amp;gt; liveness check                             [live]&lt;br /&gt;
      boot: FWSEC -&amp;amp;gt; Booter Load -&amp;amp;gt; RISC-V active -&amp;amp;gt; GSP-RM init        [live]&lt;br /&gt;
      mdev + ladder: backend joins the live session; real objects,&lt;br /&gt;
         channels, first real CE copy                                   [live]&lt;br /&gt;
      guest: nvidia.ko probes; emulation serves handshake, static config,&lt;br /&gt;
         RM battery, UVM registration                                   [live]&lt;br /&gt;
WORK  guest CUDA app -&amp;amp;gt; libcuda -&amp;amp;gt; nvidia.ko -&amp;amp;gt; GPFIFO -&amp;amp;gt; doorbell&lt;br /&gt;
      host pump decodes; eligible CE copies forwarded via module-built scratch&lt;br /&gt;
         page tables; GR: launch reaches the front-end, descriptor not seen [wall]&lt;br /&gt;
DONE  engine authors the release in guest memory; host relays via MSI-X   [gated]&lt;br /&gt;
TEARDOWN mdev remove -&amp;amp;gt; QEMU stop -&amp;amp;gt; module unload -&amp;amp;gt; clean GSP-RM shutdown&lt;br /&gt;
      -&amp;amp;gt; protected region down -&amp;amp;gt; distribution driver rebound            [live]&lt;br /&gt;
FAIL  a failed mutating operation parks the device in a locked fail-safe;&lt;br /&gt;
      never auto-retried; recovery is supervised                          [live]&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Proven capabilities ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Capability&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| Control plane (GSP boot emulation, RPC, BAR/PCI/MSI-X)&lt;br /&gt;
| done &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Driver-API baseline (init, devices, context, allocation, copies, free, destroy)&lt;br /&gt;
| done — 64/64 payload round-trip &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Software bridge for decoded memory/state operations&lt;br /&gt;
| in progress &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Device ownership, firmware staging, board-liveness checks&lt;br /&gt;
| verified live &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Power domain held active across the ownership window&lt;br /&gt;
| verified across supervised cycles &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Real GSP boot by the module, through init-done and clean release&lt;br /&gt;
| done, no reboot on clean cycles &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Host RM client and first real engine work (static config, real objects, 4 KiB CE copy)&lt;br /&gt;
| done &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Guest-copy forwarding, deferred release, hardware-primary copies, engine-authored relay, fault relay&lt;br /&gt;
| default-off, verified live; one relayed-copy mismatch under triage &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| CUDA kernel execution (&amp;lt;code&amp;gt;vectorAdd&amp;lt;/code&amp;gt;)&lt;br /&gt;
| open &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; — the launch-descriptor install path; correct results are the &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 7. The execution frontier ==&lt;br /&gt;
&lt;br /&gt;
The RM client ladder reaches the compute engine (a GR0 channel plus a compute-class object). A forwarded guest CUDA launch now reaches the front-end (ring entry fetched, methods executed) but the inline launch-descriptor install has not been observed and no grid has dispatched; context validity at dispatch is ruled out. The wall is the form of the forwarded launch method stream — see [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]. A failed mutating operation on the backend parks the device in a locked fail-safe that is never auto-retried; recovery is a supervised step.&lt;br /&gt;
&lt;br /&gt;
== 8. Safety and platform discipline ==&lt;br /&gt;
&lt;br /&gt;
* '''Dedicated GPU deployment.''' One GPU serves the vGPU service; the host uses another GPU or integrated graphics. The distribution driver stays unmodified and is unbound from that device only while the service is active.&lt;br /&gt;
* '''The board's power domain belongs to the platform.''' Releasing the last driver can power-gate the board and the power-on sequence can fail; the ownership path holds the whole board in a held-active state across the window, verifies config-space liveness, and aborts on any power-loss signature without retry.&lt;br /&gt;
* '''Supervised cycles.''' The device is driven by the module under supervised cycles with a written recovery plan. A failed mutating operation parks the device in a locked fail-safe and is never auto-retried; any reboot requires explicit human approval with a written reason and post-reboot plan first.&lt;br /&gt;
* '''Fail closed.''' No forwarding seam programs guest-derived page tables into the real MMU until the population path is proven end to end; the current forwarded path submits engine work only through module-built scratch page tables mapping already-resolved host pages.&lt;br /&gt;
&lt;br /&gt;
== 9. Sharing policy and isolation ==&lt;br /&gt;
&lt;br /&gt;
* '''Dedicated GPU (chosen):''' one GPU serves the vGPU service; a multi-GPU host gives the distribution driver its own GPU.&lt;br /&gt;
* '''Shared single GPU with the host driver bound:''' no conforming mechanism exists on this generation without vendor interfaces; it would require relaxing a constraint (vendor vGPU stack, SR-IOV hardware, or a host daemon).&lt;br /&gt;
* Isolation is one real GSP client per mdev with per-client page tables; host access to guest memory stays behind the hypervisor's per-device DMA interface, and tenant policy is a later layer on top ([[GMMU Multi-Tenant Protection|&amp;lt;code&amp;gt;GMMU-Multi-Tenant-Protection.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 10. Open questions ==&lt;br /&gt;
&lt;br /&gt;
* Firmware/host driver ABI match for the supported family on the development GPU.&lt;br /&gt;
* GPU unbind/reset lifecycle and recovery after guest faults.&lt;br /&gt;
* Which guest allocations need real VRAM and which can stay in system memory.&lt;br /&gt;
* Fault semantics and per-tenant scheduling once multiple mdevs share the service GPU.&lt;br /&gt;
&lt;br /&gt;
== 11. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/08-physical-gpu-integration.md &amp;lt;code&amp;gt;../docs/03-architecture/08-physical-gpu-integration.md&amp;lt;/code&amp;gt;] — canonical: mechanism choice and device bring-up.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/11-physical-backend-guest-wiring.md &amp;lt;code&amp;gt;../docs/03-architecture/11-physical-backend-guest-wiring.md&amp;lt;/code&amp;gt;] — canonical: the guest-wiring design.&lt;br /&gt;
* [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]], [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]] — the GR wall and the software execution plane.&lt;br /&gt;
* [[The Host Module (vgsp.ko)|&amp;lt;code&amp;gt;Host-Module.md&amp;lt;/code&amp;gt;]] — the module that owns both planes.&lt;br /&gt;
* [[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]] — page-table seams and scratch mappings.&lt;br /&gt;
* [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]], [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] — support scope and the honest status picture.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Migration_Protocol&amp;diff=23984</id>
		<title>Migration Protocol</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Migration_Protocol&amp;diff=23984"/>
		<updated>2026-10-12T04:40:59Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Migration Protocol (RPC 0x0B) =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' This page records the MIGRATE RPC (type 0x0B) as seen in firmware analysis; in emulation mode the MIGRATE RPC returns &amp;lt;code&amp;gt;-ENOTSUPP&amp;lt;/code&amp;gt;. The live migration implementation is [https://git.vgpu.io/open-iov.git/tree/kernel/migration.c &amp;lt;code&amp;gt;../kernel/migration.c&amp;lt;/code&amp;gt;]; design and status are documented in [https://git.vgpu.io/open-iov.git/tree/docs/04-implementation &amp;lt;code&amp;gt;../docs/04-implementation/&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The MIGRATE RPC (type 0x0B) implements live migration for vGPU virtual functions. It uses '''dual jump tables''' for two-phase migration operations, accessed via the primary dispatcher at 0x057A1AC0.&lt;br /&gt;
&lt;br /&gt;
== Key Addresses ==&lt;br /&gt;
&lt;br /&gt;
=== Migration Jump Tables ===&lt;br /&gt;
&lt;br /&gt;
==== Table 1: 0x04179ED8 (Primary MIGRATE branch at 0x057A1BDC) ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Index&lt;br /&gt;
! Target&lt;br /&gt;
! Decompiled&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x057A2344&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare - returns ID 0x14, checks flag at +0x7F9&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| 0x057A2320&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| 0x057A230C&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 0x057A22F8&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare - returns ID 0x10&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 0x057A2388&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 0x057A23D8&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 0x057A23AC&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| 0x057A2478&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| 0x057A2428&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| 0x057A2454&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| 0x057A2404&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| 0x057A2364&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
| Duplicate entry&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| 0x057A299C&lt;br /&gt;
| —&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
| Duplicate entry&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
| Duplicate entry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Table 2: 0x04179FBC (Primary MIGRATE branch at 0x057A1D5C) ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Index&lt;br /&gt;
! Target&lt;br /&gt;
! Decompiled&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x057A257C&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| 0x057A25E4&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| 0x057A24EC&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 0x057A2608&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 0x057A2534&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 0x057A25C0&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 0x057A24A4&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| 0x057A259C&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| 0x057A2510&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| 0x057A2558&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| 0x057A24C8&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| 0x057A262C&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| 0x057A345C&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 3: Commit&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| 0x057A36D8&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 3: Commit&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| 0x057A35D8&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 3: Commit&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| 0x057A3658&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 3: Commit&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Migration Phases ==&lt;br /&gt;
&lt;br /&gt;
=== Phase 0: Discovery (Pre-migration) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Query VF migratability&lt;br /&gt;
int gsp_migrate_query(struct gsp_vf *vf, struct migrate_query *out) {&lt;br /&gt;
    migrate_payload_t payload = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_QUERY,&lt;br /&gt;
        .subcmd = 0,&lt;br /&gt;
        .src_vf = vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = 0,&lt;br /&gt;
    };&lt;br /&gt;
    return gsp_rpc_send(vf-&amp;amp;gt;gsp, RPC_MIGRATE, &amp;amp;amp;payload, sizeof(payload), out, sizeof(*out));&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Phase 1: Prepare (Table 1, indices 0-11) ===&lt;br /&gt;
&lt;br /&gt;
'''Goal''': Quiesce VF, prepare memory state for transfer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Subcmd 3 (0x057A22F8) - Returns ID 0x10&lt;br /&gt;
int migrate_prepare_quiesce(vf_id) {&lt;br /&gt;
    // 1. Pause VF scheduling&lt;br /&gt;
    // 2. Flush pending commands&lt;br /&gt;
    // 3. Pin all VF memory&lt;br /&gt;
    // 4. Return quiesce token&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Subcmd 0 (0x057A2344) - Returns ID 0x14, checks flag at in_t1+0x7F9&lt;br /&gt;
int migrate_prepare_snapshot(vf_id, *token) {&lt;br /&gt;
    // 1. Snapshot VF register state&lt;br /&gt;
    // 2. Snapshot BAR configurations&lt;br /&gt;
    // 3. Snapshot WPR regions&lt;br /&gt;
    // 4. Snapshot page tables&lt;br /&gt;
    // 5. Return snapshot handle&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Phase 2: Transfer (Table 1 index 13, Table 2 indices 0-11) ===&lt;br /&gt;
&lt;br /&gt;
'''Goal''': Transfer memory pages to destination&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Table 2, subcmd 0 (0x057A257C)&lt;br /&gt;
int migrate_transfer_pages(vf_id, page_list, *progress) {&lt;br /&gt;
    // 1. Iterate page list&lt;br /&gt;
    // 2. For each page:&lt;br /&gt;
    //    a. Copy via DMA (0x0588F9C4)&lt;br /&gt;
    //    b. Verify checksum&lt;br /&gt;
    //    c. Mark page dirty if modified&lt;br /&gt;
    // 3. Return bytes transferred&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Table 2, subcmd 11 (0x057A262C) - Dirty page tracking&lt;br /&gt;
int migrate_track_dirty(vf_id, *dirty_bitmap) {&lt;br /&gt;
    // Return bitmap of pages dirtied since last transfer&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Phase 3: Commit (Table 2 indices 12-15) ===&lt;br /&gt;
&lt;br /&gt;
'''Goal''': Final synchronization, cutover to destination&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Subcmd 12 (0x057A345C)&lt;br /&gt;
int migrate_commit_finalize(vf_id, dst_vf_id) {&lt;br /&gt;
    // 1. Final dirty page transfer&lt;br /&gt;
    // 2. Transfer register state&lt;br /&gt;
    // 3. Activate destination VF&lt;br /&gt;
    // 4. Release source VF resources&lt;br /&gt;
    // 5. Notify completion&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Subcmd 13 (0x057A36D8)&lt;br /&gt;
int migrate_commit_verify(vf_id, *verify_result) {&lt;br /&gt;
    // 1. Verify memory integrity&lt;br /&gt;
    // 2. Verify register state&lt;br /&gt;
    // 3. Verify device state&lt;br /&gt;
    // 4. Return PASS/FAIL&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Phase 4: Cleanup (Post-migration) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int migrate_cleanup(src_vf_id) {&lt;br /&gt;
    // 1. Release pinned memory&lt;br /&gt;
    // 2. Free snapshot buffers&lt;br /&gt;
    // 3. Remove WPR regions&lt;br /&gt;
    // 4. Destroy migration context&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Migration Message Format ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t phase;         // MIGRATE_PHASE_*&lt;br /&gt;
    uint32_t subcmd;        // Sub-command index (0-15 per table)&lt;br /&gt;
    uint64_t src_vf;        // Source VF ID&lt;br /&gt;
    uint64_t dst_vf;        // Destination VF ID&lt;br /&gt;
    uint64_t data_ptr;      // Data buffer (page list, bitmap, etc.)&lt;br /&gt;
    uint64_t data_size;     // Buffer size&lt;br /&gt;
    uint32_t flags;         // MIGRATE_LIVE, MIGRATE_POSTCOPY, etc.&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
    uint64_t token;         // Opaque migration token&lt;br /&gt;
} __attribute__((packed)) migrate_payload_t;&lt;br /&gt;
&lt;br /&gt;
#define MIGRATE_PHASE_QUERY     0&lt;br /&gt;
#define MIGRATE_PHASE_PREPARE   1&lt;br /&gt;
#define MIGRATE_PHASE_TRANSFER  2&lt;br /&gt;
#define MIGRATE_PHASE_COMMIT    3&lt;br /&gt;
#define MIGRATE_PHASE_CLEANUP   4&lt;br /&gt;
&lt;br /&gt;
#define MIGRATE_FLAG_LIVE       (1&amp;amp;lt;&amp;amp;lt;0)    // Live migration&lt;br /&gt;
#define MIGRATE_FLAG_POSTCOPY   (1&amp;amp;lt;&amp;amp;lt;1)    // Post-copy mode&lt;br /&gt;
#define MIGRATE_FLAG_AUTO_COMMIT (1&amp;amp;lt;&amp;amp;lt;2)  // Auto-commit after transfer&lt;br /&gt;
#define MIGRATE_FLAG_VERIFY     (1&amp;amp;lt;&amp;amp;lt;3)    // Verify integrity&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sub-Command Descriptors (Returned by Handlers) ==&lt;br /&gt;
&lt;br /&gt;
All migration handlers follow the primary dispatcher pattern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t subcmd_id;     // Constant: 0x10, 0x14, etc.&lt;br /&gt;
    uint8_t  echo_flags_b;  // Copy of input flags_b&lt;br /&gt;
    uint8_t  echo_flags_a;  // Copy of input flags_a&lt;br /&gt;
    uint8_t  echo_flags_c;  // Copy of input flags_c&lt;br /&gt;
} migrate_descriptor_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Known Subcmd IDs''':&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Subcmd&lt;br /&gt;
! ID&lt;br /&gt;
! Phase&lt;br /&gt;
|-&lt;br /&gt;
| 0x057A22F8 (Table1[3])&lt;br /&gt;
| 0x10&lt;br /&gt;
| Prepare&lt;br /&gt;
|-&lt;br /&gt;
| 0x057A2344 (Table1[0])&lt;br /&gt;
| 0x14&lt;br /&gt;
| Prepare&lt;br /&gt;
|-&lt;br /&gt;
| Others&lt;br /&gt;
| TBD&lt;br /&gt;
| Transfer/Commit&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== vGPU-IO Integration ==&lt;br /&gt;
&lt;br /&gt;
=== Migration State Machine ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef enum {&lt;br /&gt;
    MIG_STATE_IDLE = 0,&lt;br /&gt;
    MIG_STATE_QUERY,&lt;br /&gt;
    MIG_STATE_PREPARE,&lt;br /&gt;
    MIG_STATE_TRANSFER,&lt;br /&gt;
    MIG_STATE_COMMIT,&lt;br /&gt;
    MIG_STATE_CLEANUP,&lt;br /&gt;
    MIG_STATE_FAILED,&lt;br /&gt;
    MIG_STATE_COMPLETED&lt;br /&gt;
} mig_state_t;&lt;br /&gt;
&lt;br /&gt;
struct gsp_migration {&lt;br /&gt;
    struct gsp_vf *vf;&lt;br /&gt;
    mig_state_t state;&lt;br /&gt;
    uint64_t token;&lt;br /&gt;
    uint64_t dst_vf;&lt;br /&gt;
    struct migrate_progress progress;&lt;br /&gt;
    struct completion comp;&lt;br /&gt;
    struct mutex lock;&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Migration Coordinator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_migration_start(struct gsp_vf *vf, uint64_t dst_vf) {&lt;br /&gt;
    struct gsp_migration *mig = kzalloc(sizeof(*mig), GFP_KERNEL);&lt;br /&gt;
    vf-&amp;amp;gt;migration = mig;&lt;br /&gt;
    mig-&amp;amp;gt;vf = vf;&lt;br /&gt;
    mig-&amp;amp;gt;dst_vf = dst_vf;&lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_QUERY;&lt;br /&gt;
    &lt;br /&gt;
    // Phase 0: Query&lt;br /&gt;
    struct migrate_query qry;&lt;br /&gt;
    gsp_migrate_query(vf, &amp;amp;amp;qry);&lt;br /&gt;
    if (!qry.migratable) return -EINVAL;&lt;br /&gt;
    &lt;br /&gt;
    // Phase 1: Prepare&lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_PREPARE;&lt;br /&gt;
    migrate_payload_t prep = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_PREPARE,&lt;br /&gt;
        .subcmd = 3,  // Quiesce&lt;br /&gt;
        .src_vf = vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = dst_vf,&lt;br /&gt;
    };&lt;br /&gt;
    migrate_descriptor_t desc;&lt;br /&gt;
    gsp_rpc_send(vf-&amp;amp;gt;gsp, RPC_MIGRATE, &amp;amp;amp;prep, sizeof(prep), &amp;amp;amp;desc, sizeof(desc));&lt;br /&gt;
    mig-&amp;amp;gt;token = desc.subcmd_id;  // Use returned token&lt;br /&gt;
    &lt;br /&gt;
    // Phase 2: Transfer (iterative)&lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_TRANSFER;&lt;br /&gt;
    while (!gsp_migration_transfer_iter(mig)) {&lt;br /&gt;
        msleep(10);  // Throttle&lt;br /&gt;
        if (signal_pending(current)) break;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Phase 3: Commit&lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_COMMIT;&lt;br /&gt;
    migrate_payload_t commit = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_COMMIT,&lt;br /&gt;
        .subcmd = 12,&lt;br /&gt;
        .src_vf = vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = dst_vf,&lt;br /&gt;
        .token = mig-&amp;amp;gt;token,&lt;br /&gt;
        .flags = MIGRATE_FLAG_VERIFY,&lt;br /&gt;
    };&lt;br /&gt;
    gsp_rpc_send(vf-&amp;amp;gt;gsp, RPC_MIGRATE, &amp;amp;amp;commit, sizeof(commit), NULL, 0);&lt;br /&gt;
    &lt;br /&gt;
    // Phase 4: Cleanup&lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_CLEANUP;&lt;br /&gt;
    gsp_migration_cleanup(mig);&lt;br /&gt;
    &lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_COMPLETED;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Transfer Iteration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;bool gsp_migration_transfer_iter(struct gsp_migration *mig) {&lt;br /&gt;
    migrate_payload_t xfer = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_TRANSFER,&lt;br /&gt;
        .subcmd = 0,&lt;br /&gt;
        .src_vf = mig-&amp;amp;gt;vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = mig-&amp;amp;gt;dst_vf,&lt;br /&gt;
        .data_ptr = (uint64_t)mig-&amp;amp;gt;progress.page_list,&lt;br /&gt;
        .data_size = mig-&amp;amp;gt;progress.page_count * sizeof(uint64_t),&lt;br /&gt;
        .token = mig-&amp;amp;gt;token,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    struct migrate_progress prog;&lt;br /&gt;
    int ret = gsp_rpc_send(mig-&amp;amp;gt;vf-&amp;amp;gt;gsp, RPC_MIGRATE, &lt;br /&gt;
                           &amp;amp;amp;xfer, sizeof(xfer), &amp;amp;amp;prog, sizeof(prog));&lt;br /&gt;
    &lt;br /&gt;
    if (ret) return true;  // Error = done&lt;br /&gt;
    &lt;br /&gt;
    mig-&amp;amp;gt;progress.bytes_transferred += prog.bytes_transferred;&lt;br /&gt;
    mig-&amp;amp;gt;progress.pages_transferred += prog.pages_transferred;&lt;br /&gt;
    mig-&amp;amp;gt;progress.dirty_pages = prog.dirty_pages;&lt;br /&gt;
    &lt;br /&gt;
    // Check if more dirty pages to transfer&lt;br /&gt;
    if (prog.dirty_pages &amp;amp;gt; 0 &amp;amp;amp;&amp;amp;amp; !(mig-&amp;amp;gt;flags &amp;amp;amp; MIGRATE_FLAG_POSTCOPY)) {&lt;br /&gt;
        return false;  // Continue iterating&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return true;  // Transfer complete&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Post-Copy Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_migration_postcopy(struct gsp_migration *mig) {&lt;br /&gt;
    // Enable post-copy on destination&lt;br /&gt;
    migrate_payload_t pc = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_TRANSFER,&lt;br /&gt;
        .subcmd = 11,  // Dirty tracking&lt;br /&gt;
        .src_vf = mig-&amp;amp;gt;vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = mig-&amp;amp;gt;dst_vf,&lt;br /&gt;
        .flags = MIGRATE_FLAG_POSTCOPY,&lt;br /&gt;
        .token = mig-&amp;amp;gt;token,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    // Page fault handler on destination&lt;br /&gt;
    gsp_page_fault_handler = gsp_migration_page_fault;&lt;br /&gt;
    &lt;br /&gt;
    return gsp_rpc_send(mig-&amp;amp;gt;vf-&amp;amp;gt;gsp, RPC_MIGRATE, &amp;amp;amp;pc, sizeof(pc), NULL, 0);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Integration with BAR/WPR ==&lt;br /&gt;
&lt;br /&gt;
=== BAR State Migration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_migration_bar_save(struct gsp_migration *mig) {&lt;br /&gt;
    // Save BAR1 aperture, force access state&lt;br /&gt;
    struct bar_save_msg bar_save = {&lt;br /&gt;
        .vf_id = mig-&amp;amp;gt;vf-&amp;amp;gt;id,&lt;br /&gt;
        .bar = 1,&lt;br /&gt;
    };&lt;br /&gt;
    return gsp_rpc_send(mig-&amp;amp;gt;vf-&amp;amp;gt;gsp, RPC_BAR_TRAP,&lt;br /&gt;
                        BAR_SUBCMD_SAVE, &amp;amp;amp;bar_save, sizeof(bar_save),&lt;br /&gt;
                        mig-&amp;amp;gt;bar_state_buf, &amp;amp;amp;mig-&amp;amp;gt;bar_state_size);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int gsp_migration_bar_restore(struct gsp_migration *mig) {&lt;br /&gt;
    // Restore BAR1 on destination&lt;br /&gt;
    struct bar_restore_msg bar_restore = {&lt;br /&gt;
        .vf_id = mig-&amp;amp;gt;dst_vf,&lt;br /&gt;
        .bar = 1,&lt;br /&gt;
        .data = mig-&amp;amp;gt;bar_state_buf,&lt;br /&gt;
        .data_size = mig-&amp;amp;gt;bar_state_size,&lt;br /&gt;
    };&lt;br /&gt;
    return gsp_rpc_send(mig-&amp;amp;gt;vf-&amp;amp;gt;gsp, RPC_BAR_TRAP,&lt;br /&gt;
                        BAR_SUBCMD_RESTORE, &amp;amp;amp;bar_restore, sizeof(bar_restore));&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WPR Region Migration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_migration_wpr_save(struct gsp_migration *mig) {&lt;br /&gt;
    // Save WPR regions for VF&lt;br /&gt;
    migrate_payload_t wpr = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_PREPARE,&lt;br /&gt;
        .subcmd = 4,  // WPR snapshot&lt;br /&gt;
        .src_vf = mig-&amp;amp;gt;vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = mig-&amp;amp;gt;dst_vf,&lt;br /&gt;
        .token = mig-&amp;amp;gt;token,&lt;br /&gt;
    };&lt;br /&gt;
    return gsp_rpc_send(mig-&amp;amp;gt;vf-&amp;amp;gt;gsp, RPC_MIGRATE, &amp;amp;amp;wpr, sizeof(wpr), NULL, 0);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error Handling ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Phase&lt;br /&gt;
! Error&lt;br /&gt;
! Recovery&lt;br /&gt;
|-&lt;br /&gt;
| Prepare&lt;br /&gt;
| EBUSY&lt;br /&gt;
| Wait, retry&lt;br /&gt;
|-&lt;br /&gt;
| Prepare&lt;br /&gt;
| ENOMEM&lt;br /&gt;
| Reduce snapshot size&lt;br /&gt;
|-&lt;br /&gt;
| Transfer&lt;br /&gt;
| ETIMEDOUT&lt;br /&gt;
| Checkpoint, retry&lt;br /&gt;
|-&lt;br /&gt;
| Transfer&lt;br /&gt;
| EIO&lt;br /&gt;
| Failover to post-copy&lt;br /&gt;
|-&lt;br /&gt;
| Commit&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Rollback to source&lt;br /&gt;
|-&lt;br /&gt;
| Commit&lt;br /&gt;
| ENOSPC&lt;br /&gt;
| Expand destination&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
&lt;br /&gt;
=== Migration Trace Points ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;trace_gsp_mig_phase(vf_id, phase, subcmd, token);&lt;br /&gt;
trace_gsp_mig_transfer(vf_id, pages, bytes, dirty);&lt;br /&gt;
trace_gsp_mig_commit(vf_id, status, verify);&lt;br /&gt;
trace_gsp_mig_error(vf_id, phase, error);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GSP Log Strings ===&lt;br /&gt;
&lt;br /&gt;
Search for migration-related strings in firmware:&lt;br /&gt;
&lt;br /&gt;
* Migration phase markers&lt;br /&gt;
* Page transfer progress&lt;br /&gt;
* Commit verification results&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
* Primary Dispatcher MIGRATE branches: 0x057A1BDC, 0x057A1D54&lt;br /&gt;
* Jump Table 1: 0x04179ED8 (16 entries)&lt;br /&gt;
* Jump Table 2: 0x04179FBC (16 entries)&lt;br /&gt;
* Decompiled handlers: 28 functions in decompiled/&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Introduction_to_GMMU&amp;diff=23983</id>
		<title>Introduction to GMMU</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Introduction_to_GMMU&amp;diff=23983"/>
		<updated>2026-10-12T04:40:58Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Introduction to the GMMU =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' A from-first-principles introduction to the GPU Memory Management Unit (GMMU): what it translates, how its page tables work on our Turing reference, how the host module uses them, and how the GMMU relates to the CPU MMU and the platform IOMMU/SMMU. The architecture chapter is [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/05-gmmu-amap-hal-gr.md &amp;lt;code&amp;gt;../docs/03-architecture/05-gmmu-amap-hal-gr.md&amp;lt;/code&amp;gt;]; the isolation policy authority is [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/14-multi-tenant-gmmu-protection.md &amp;lt;code&amp;gt;../docs/03-architecture/14-multi-tenant-gmmu-protection.md&amp;lt;/code&amp;gt;] (condensed in [[GMMU Multi-Tenant Protection|&amp;lt;code&amp;gt;GMMU-Multi-Tenant-Protection.md&amp;lt;/code&amp;gt;]]).&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Evidence discipline.''' Hardware-format claims condense the tracked field catalogue [https://git.vgpu.io/open-iov.git/tree/debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md &amp;lt;code&amp;gt;../debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md&amp;lt;/code&amp;gt;] and live observations; numeric IDs, layouts and code anchors are cited, and no timing/cycle claim is made.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Status: 2026-10-11, tree &amp;lt;code&amp;gt;master @ 08f39c2f&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed with the stock guest driver; &amp;lt;code&amp;gt;[proven]&amp;lt;/code&amp;gt; hardware-format fact; &amp;lt;code&amp;gt;[hypothesis]&amp;lt;/code&amp;gt; unexercised; &amp;lt;code&amp;gt;[design]&amp;lt;/code&amp;gt; not built.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. What the GMMU is ==&lt;br /&gt;
&lt;br /&gt;
The '''GMMU (GPU Memory Management Unit)''' is the address-translation hardware inside the GPU. Every engine — GR (shaders and CUDA kernels), CE (copy engines), SEC2, the video engines — addresses memory through '''GPU virtual addresses (VAs)''', and the GMMU translates each VA into a physical address: an offset in GPU local memory ('''vidmem'''/VRAM), an address in system memory ('''sysmem'''), or a peer GPU's memory across a fabric.&lt;br /&gt;
&lt;br /&gt;
It is a paged MMU, conceptually the CPU MMU's sibling:&lt;br /&gt;
&lt;br /&gt;
* '''Multi-level page tables''' describe the mappings; the root is a '''page directory base (PDB)'''.&lt;br /&gt;
* A '''TLB''' caches translations so the walk is not paid per access.&lt;br /&gt;
* Translation failures raise '''faults''' (invalid/missing leaf, missing table), reported through engine fault buffers.&lt;br /&gt;
* '''Each context has its own page directory (VA space)''', so one context cannot name another context's mappings — this is the hardware isolation boundary the project builds multi-tenancy on.&lt;br /&gt;
&lt;br /&gt;
What makes it ''not'' just &amp;quot;the CPU MMU on a GPU&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* The tables live in GPU-visible memory (vidmem or sysmem), and each directory entry says which aperture the next level lives in.&lt;br /&gt;
* Entries carry GPU-specific '''aperture''' (which physical space) and '''memory-kind''' fields that the CPU MMU does not have.&lt;br /&gt;
* The &amp;quot;physical&amp;quot; addresses inside the tables are '''guest-physical addresses or emulated-VRAM offsets''' in our virtualized setting; the host module owns the resolution to real host addresses (§4.2). On a bare-metal GPU the same structures point at real vidmem/sysmem.&lt;br /&gt;
&lt;br /&gt;
For this project the GMMU matters three ways: the guest driver programs it exactly as on bare metal (no guest patches); the guest's page tables are the ground truth for ''where its memory actually is''; and the per-context page directory is the only proven hardware isolation primitive available on the reference generation (§4.2).&lt;br /&gt;
&lt;br /&gt;
== 2. The three MMUs: CPU MMU, GMMU, IOMMU/SMMU ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! &lt;br /&gt;
! CPU MMU&lt;br /&gt;
! GMMU&lt;br /&gt;
! IOMMU / SMMU&lt;br /&gt;
|-&lt;br /&gt;
| Translates&lt;br /&gt;
| process VA → host physical address&lt;br /&gt;
| engine GPU VA → GPU physical (vidmem / sysmem / peer)&lt;br /&gt;
| device DMA address → host physical address&lt;br /&gt;
|-&lt;br /&gt;
| Lives in&lt;br /&gt;
| the CPU core&lt;br /&gt;
| the GPU&lt;br /&gt;
| the host platform (IOMMU: Intel VT-d / AMD-Vi) or the SoC (SMMU, ARM)&lt;br /&gt;
|-&lt;br /&gt;
| Programmed by&lt;br /&gt;
| the OS kernel (per-process tables)&lt;br /&gt;
| the GPU driver / RM (the ''guest'' driver here)&lt;br /&gt;
| the hypervisor / OS (per-device or per-VM domains)&lt;br /&gt;
|-&lt;br /&gt;
| Table unit&lt;br /&gt;
| per-process page tables (e.g. CR3)&lt;br /&gt;
| per-context page directory (VA space)&lt;br /&gt;
| per-device/per-VM translation domain&lt;br /&gt;
|-&lt;br /&gt;
| Isolation scope&lt;br /&gt;
| process ↔ process&lt;br /&gt;
| context ↔ context (engine-level)&lt;br /&gt;
| VM/device ↔ VM/device (platform DMA)&lt;br /&gt;
|-&lt;br /&gt;
| In our stack&lt;br /&gt;
| guest and host kernels&lt;br /&gt;
| guest driver builds the tables; host walks or plants its own&lt;br /&gt;
| hypervisor enforces it; the module resolves GPAs itself when it needs host addresses&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
They are three instances of the same idea — ''page tables plus a TLB give virtual memory and isolation to an agent'' — at three different points in the address path, owned by three different software layers. In a virtualized guest a GPU access passes through '''two''' of them:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;engine (GR / CE)&lt;br /&gt;
   │  GPU VA&lt;br /&gt;
   ▼&lt;br /&gt;
GMMU  (inside the GPU, driven by the guest's page tables)&lt;br /&gt;
   │  guest physical address (GPA) / GPU local address&lt;br /&gt;
   ▼&lt;br /&gt;
IOMMU / SMMU  (in the host platform, programmed by the hypervisor for this VM)&lt;br /&gt;
   │  host physical address (HPA)&lt;br /&gt;
   ▼&lt;br /&gt;
host DRAM / real VRAM&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two stages are independent: the '''GMMU''' decides ''which guest page'' an engine touches; the '''IOMMU/SMMU''' decides ''whether this device may reach that page at all'' and where it lives in host memory. GMMU isolation between guest contexts is the GPU driver/RM's job; IOMMU isolation between VMs is the platform's job.&lt;br /&gt;
&lt;br /&gt;
'''How the two meet in this project:'''&lt;br /&gt;
&lt;br /&gt;
* In real vGPU, the host vGPU manager uses the platform IOMMU to establish the GPU's view of guest memory. Here the host module does the equivalent resolution itself.&lt;br /&gt;
* On the reference host the physical GPU's IOMMU group is an '''identity domain''' (all-RAM identity) and the mediated device registers as an '''emulated-IOMMU VFIO device''': its type-1 container holds guest DMA mappings privately and no kernel &amp;lt;code&amp;gt;iommu_domain&amp;lt;/code&amp;gt; exists for it, so &amp;lt;code&amp;gt;iommu_iova_to_phys&amp;lt;/code&amp;gt; cannot translate guest GPAs. Guest RAM is backed by a QEMU shared file and the module translates GPA→HPA through that file's page cache, behind the active-mdev gate (a per-mdev-gated translation, ''not'' itself an IOMMU guarantee).&lt;br /&gt;
* The project rule is explicit: '''memory isolation is the platform IOMMU's job, and we never weaken it''' — DMA only through the hypervisor-provided interface for the device's own VM, no global mappings, fail closed if a required isolation property cannot be established.&lt;br /&gt;
* On aarch64 hosts the '''SMMU''' plays the IOMMU's role; page sizes, cache attributes and SMMU behaviour are on the host-portability list for the Grace/GB10 targets.&lt;br /&gt;
&lt;br /&gt;
== 3. How the GMMU works (Turing reference) ==&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Page-tree geometry ===&lt;br /&gt;
&lt;br /&gt;
The Turing page-tree path inherits the Pascal/Volta geometry and uses the '''VER2''' entry encoding. Depths run root (0) to leaf (4); VA width is '''49 bits''':&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Depth&lt;br /&gt;
! HW level&lt;br /&gt;
! VA bits&lt;br /&gt;
! Index bits&lt;br /&gt;
! Entry size&lt;br /&gt;
! Role&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| PDE3&lt;br /&gt;
| 48:47&lt;br /&gt;
| 2&lt;br /&gt;
| 8 B&lt;br /&gt;
| pointer PDE&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| PDE2&lt;br /&gt;
| 46:38&lt;br /&gt;
| 9&lt;br /&gt;
| 8 B&lt;br /&gt;
| pointer PDE&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| PDE1&lt;br /&gt;
| 37:29&lt;br /&gt;
| 9&lt;br /&gt;
| 8 B&lt;br /&gt;
| pointer PDE (&amp;lt;code&amp;gt;NO_ATS&amp;lt;/code&amp;gt; set here)&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| PDE0&lt;br /&gt;
| 28:21&lt;br /&gt;
| 8&lt;br /&gt;
| 16 B (dual) / 8 B (2 MB leaf)&lt;br /&gt;
| dual 64K/4K PDE, or a 2 MB leaf PTE&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| PTE&lt;br /&gt;
| 20:12 (4 KB) / 20:16 (64 KB)&lt;br /&gt;
| 9 / 5&lt;br /&gt;
| 8 B&lt;br /&gt;
| leaf PTE&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Supported page sizes are '''2 MB''' (depth 3), '''64 KB''' and '''4 KB''' (depth 4). A leaf entry alone does not say 4 KB vs 64 KB — the table's depth and page-size context do — so decoders must report &amp;lt;code&amp;gt;4k_or_64k&amp;lt;/code&amp;gt; rather than guess.&lt;br /&gt;
&lt;br /&gt;
=== 3.2 Entry encoding (VER2) ===&lt;br /&gt;
&lt;br /&gt;
'''Leaf PTE (8 bytes):'''&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Bits&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;valid&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0&lt;br /&gt;
| entry is present&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;aperture&amp;lt;/code&amp;gt;&lt;br /&gt;
| 2:1&lt;br /&gt;
| 0 video, 1 peer, 2 system coherent, 3 system non-coherent&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volatile&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3&lt;br /&gt;
| cache/volatility bit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;encrypted&amp;lt;/code&amp;gt;&lt;br /&gt;
| 4&lt;br /&gt;
| encrypted memory&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;privilege&amp;lt;/code&amp;gt;&lt;br /&gt;
| 5&lt;br /&gt;
| privileged access&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;read_only&amp;lt;/code&amp;gt;&lt;br /&gt;
| 6&lt;br /&gt;
| write protection&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;atomic_disable&amp;lt;/code&amp;gt;&lt;br /&gt;
| 7&lt;br /&gt;
| atomics disabled&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;address_sys&amp;lt;/code&amp;gt;&lt;br /&gt;
| 53:8&lt;br /&gt;
| system-aperture address bits (PA 53:12)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;address_vid&amp;lt;/code&amp;gt;&lt;br /&gt;
| 32:8&lt;br /&gt;
| video/peer address bits (PA 36:12)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;peer_id&amp;lt;/code&amp;gt;&lt;br /&gt;
| 35:33&lt;br /&gt;
| peer/fabric id (peer aperture)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;comptagline&amp;lt;/code&amp;gt;&lt;br /&gt;
| 55:36&lt;br /&gt;
| compression tag (overloaded as high address bits for the 47-bit peer case)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;kind&amp;lt;/code&amp;gt;&lt;br /&gt;
| 63:56&lt;br /&gt;
| memory kind id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Directory PDE (8 bytes)''' is the same shape with one discriminator change: bit 0 is &amp;lt;code&amp;gt;is_pde_pointer&amp;lt;/code&amp;gt; (0 = pointer to a lower table, 1 = a 2 MB leaf PTE), and '''aperture 0 means invalid at directory level''' (it means video memory at leaf level). Depth 2 sets &amp;lt;code&amp;gt;NO_ATS&amp;lt;/code&amp;gt; (bit 5).&lt;br /&gt;
&lt;br /&gt;
'''Dual PDE0 (16 bytes)''' holds two halves for mixed 64K/4K tables: BIG (low 64 bits) and SMALL (high 64 bits); bit 0 discriminates the whole slot.&lt;br /&gt;
&lt;br /&gt;
Live guest note: the client's leaf entries in the format we observe are &amp;lt;code&amp;gt;PA[47:12] | flags&amp;lt;/code&amp;gt;, with &amp;lt;code&amp;gt;flags = 0xe&amp;lt;/code&amp;gt; for a valid system-memory leaf. The &amp;lt;code&amp;gt;kind&amp;lt;/code&amp;gt; field carries numeric memory-kind ids (243 named values); common compute values are &amp;lt;code&amp;gt;0x00 PITCH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x06 GENERIC_MEMORY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x07 INVALID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x0F SMSKED_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0xFE GENERIC_16BX2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The decoder (&amp;lt;code&amp;gt;sim/gmmu_pte.py&amp;lt;/code&amp;gt;, docs/43) is decode-only: unsupported encodings fail closed, set bits not covered by a named field are reported as reserved, and nothing is guessed.&lt;br /&gt;
&lt;br /&gt;
=== 3.3 Walking, caching and faults ===&lt;br /&gt;
&lt;br /&gt;
A walk starts at the channel's '''page-directory base''' and follows &amp;lt;code&amp;gt;PDE3 → PDE2 → PDE1 → PDE0 → PTE&amp;lt;/code&amp;gt;; the leaf yields the physical address, page size, aperture and access permissions. The TLB caches results, and there is a second, coarser cache that matters operationally:&lt;br /&gt;
&lt;br /&gt;
* '''PTE fetch-line rule (learned live):''' the engine caches PTE fetches at '''128-byte (16-PTE) granularity''', and the forwarding code has '''no invalidate path'''. A runtime PTE write into a line the GMMU has already walked is invisible to the engine. Consequences: page-table slots for a guest window are '''pre-built before any engine access''', and each forwarded copy pair consumes a whole fresh line from a pre-zeroed pool (16 page-table pages, capacity 512 pairs per boot in the current design) — a line is never reused within a boot.&lt;br /&gt;
* '''Faults:''' invalid or missing leaves and missing tables raise GMMU faults; the driver allocates fault buffers whose sizes come from &amp;lt;code&amp;gt;INTERNAL_GMMU_GET_STATIC_INFO&amp;lt;/code&amp;gt; (control &amp;lt;code&amp;gt;0x20800a59&amp;lt;/code&amp;gt;): '''64 KB replayable / 4 KB legacy''' — the values the emulation serves, because a wrong value breaks UVM early.&lt;br /&gt;
&lt;br /&gt;
== 4. How the GMMU is used ==&lt;br /&gt;
&lt;br /&gt;
=== 4.1 Guest side (the stock driver) ===&lt;br /&gt;
&lt;br /&gt;
* The guest driver allocates VA spaces and '''builds the page tables''', then publishes the directory per channel/context through &amp;lt;code&amp;gt;SET_PAGE_DIRECTORY&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;hVASpace&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;chId&amp;lt;/code&amp;gt;; the host records the directory per owner in &amp;lt;code&amp;gt;kernel/gsp_rm_emulation.c:3307-3319&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Memory descriptors carry an aperture: &amp;lt;code&amp;gt;ADDR_SYSMEM = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ADDR_FBMEM = 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* '''Server-owned ranges:''' &amp;lt;code&amp;gt;COPY_SERVER_RESERVED_PDES&amp;lt;/code&amp;gt; (control &amp;lt;code&amp;gt;0x90f10106&amp;lt;/code&amp;gt;) tells the client that some page-table ranges are populated by the &amp;quot;server&amp;quot; (us). The exact division of labour for &amp;lt;code&amp;gt;RESERVE_ENTRIES&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;RELEASE_ENTRIES&amp;lt;/code&amp;gt; and invalidations is a tracked known-unknown.&lt;br /&gt;
* Channels submit push buffers that reference GPU VAs; the engines walk the GMMU to reach the data.&lt;br /&gt;
&lt;br /&gt;
=== 4.2 Host side (&amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt;) ===&lt;br /&gt;
&lt;br /&gt;
* '''Truth.''' The host resolves guest VAs by '''walking the driver-published page directories itself''' (the trusted GMMU walk in &amp;lt;code&amp;gt;kernel/gsp_sema_service.c&amp;lt;/code&amp;gt;, VER2 geometry at &amp;lt;code&amp;gt;:1058-1072&amp;lt;/code&amp;gt;, decode &amp;lt;code&amp;gt;:1093&amp;lt;/code&amp;gt;, walk &amp;lt;code&amp;gt;:1174&amp;lt;/code&amp;gt;), plus injected pins and content-keyed rescue when neither names a mapping. This is what lets the software path apply a semaphore release to the correct host page.&lt;br /&gt;
* '''Forwarding.''' For real CE copies the module builds its '''own scratch page tables''' that map already-resolved host pages (guest RAM through the shared file; shadow pages through the emulated-VRAM mapping), under the fetch-line rules of §3.3. Real guest page tables are ''not yet'' programmed into the real MMU — guest submission on hardware is the end state (P6).&lt;br /&gt;
* '''Emulation.''' Guest vidmem is a private host-RAM buffer per mdev (&amp;lt;code&amp;gt;kernel/bar_init.c:68-77&amp;lt;/code&amp;gt;); FB-aperture accesses stay inside the owning mdev's buffer, and guest RAM is reached only through the hypervisor's per-mdev DMA interface (&amp;lt;code&amp;gt;vfio_dma_rw&amp;lt;/code&amp;gt;).&lt;br /&gt;
* '''Isolation.''' The per-context page directory is the '''only proven hardware isolation primitive''' on this generation: the VER2 PTE/PDE has '''no tenant/ACL/PASID field''' (proven absence in the named field set; &amp;lt;code&amp;gt;peer_id&amp;lt;/code&amp;gt; is a fabric peer selector, not a security domain). &amp;lt;code&amp;gt;read_only&amp;lt;/code&amp;gt; (bit 6) is a proven ''format'' field, but its ''enforcement'' is a &amp;lt;code&amp;gt;[hypothesis]&amp;lt;/code&amp;gt; until the M7 supervised probe. The multi-tenant design therefore places decisions in '''topology''' (which directory a page appears in, which channel may name it) plus software validation and audit in the execution plane — see [[GMMU Multi-Tenant Protection|&amp;lt;code&amp;gt;GMMU-Multi-Tenant-Protection.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
* '''Versioning.''' GMMU controls, static info and entry formats are version/hardware-keyed; formats are expected to differ per generation and must be re-derived by measurement, never guessed.&lt;br /&gt;
&lt;br /&gt;
=== 4.3 Tooling built around it ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tool / doc&lt;br /&gt;
! Question it answers&lt;br /&gt;
|-&lt;br /&gt;
| PTE decoder &amp;lt;code&amp;gt;sim/gmmu_pte.py&amp;lt;/code&amp;gt; + [https://git.vgpu.io/open-iov.git/tree/debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md docs/43]&lt;br /&gt;
| decode a captured entry field-by-field (decode-only, fail closed)&lt;br /&gt;
|-&lt;br /&gt;
| Walker &amp;lt;code&amp;gt;sim/gmmu_walk.py&amp;lt;/code&amp;gt; + [https://git.vgpu.io/open-iov.git/tree/debug/risc-v-gsp-rm-vm/docs/48-GMMU-WALK-AND-LAUNCH-AUDIT.md docs/48]&lt;br /&gt;
| walk a captured PDB to the leaf mapping or the exact fault (4K/2M validated against a live captured channel PDB; 64K modelled)&lt;br /&gt;
|-&lt;br /&gt;
| Launch audit &amp;lt;code&amp;gt;harness/launch_audit.py&amp;lt;/code&amp;gt; + docs/48&lt;br /&gt;
| where the engine would read/write each leg of a submission: &amp;lt;code&amp;gt;ok&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;pa_mismatch&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;unmapped&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;access_denied&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Oracle workflow [https://git.vgpu.io/open-iov.git/tree/debug/risc-v-gsp-rm-vm/docs/44-GMMU-ORACLE-AND-WORKFLOW.md docs/44]&lt;br /&gt;
| compare simulated vs observed GMMU/FBIF register values, per register, with fidelity labels&lt;br /&gt;
|-&lt;br /&gt;
| Observe-only windows [https://git.vgpu.io/open-iov.git/tree/debug/risc-v-gsp-rm-vm/docs/42-GMMU-FBIF-OBSERVABILITY.md docs/42]&lt;br /&gt;
| record what firmware touches in the GMMU register windows without faking semantics&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 5. Limits and open questions ==&lt;br /&gt;
&lt;br /&gt;
* '''&amp;lt;code&amp;gt;read_only&amp;lt;/code&amp;gt; enforcement''' is unproven (M7 supervised probe); '''encryption (CCS) semantics''' are unstudied. Neither can be assumed as a tenant boundary.&lt;br /&gt;
* '''Invalidation semantics''' are not fully modelled: the 128-byte fetch-line observation is live evidence, not a complete invalidate contract.&lt;br /&gt;
* The '''64K dual path''' is modelled from the format definitions, not yet validated against a capture.&lt;br /&gt;
* '''Newer generations''' (Ampere/Hopper/Blackwell, GB10) are expected to change the entry format; each must be re-derived. RM 610 work sits behind its own human approval gate.&lt;br /&gt;
* '''No timing/cycle claims''' are made anywhere here; zero hits in a run are a coverage fact, not proof of dead code.&lt;br /&gt;
* Multi-mdev isolation is first a '''service-state-ownership''' problem (host tables keyed by guest-chosen handles/VAs alone collide); GMMU policy is built on top of that fix, not instead of it.&lt;br /&gt;
&lt;br /&gt;
== 6. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/05-gmmu-amap-hal-gr.md &amp;lt;code&amp;gt;../docs/03-architecture/05-gmmu-amap-hal-gr.md&amp;lt;/code&amp;gt;] — architecture chapter: GMMU, AMAPlib/HALs, channels, runlists, GR.&lt;br /&gt;
* [[GMMU Multi-Tenant Protection|&amp;lt;code&amp;gt;GMMU-Multi-Tenant-Protection.md&amp;lt;/code&amp;gt;]] — the isolation design condensed.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/14-multi-tenant-gmmu-protection.md &amp;lt;code&amp;gt;../docs/03-architecture/14-multi-tenant-gmmu-protection.md&amp;lt;/code&amp;gt;] — canonical multi-tenant GMMU policy.&lt;br /&gt;
* [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]] — how guest work becomes physical execution; the fetch-line rule in context.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/11-physical-backend-guest-wiring.md &amp;lt;code&amp;gt;../docs/03-architecture/11-physical-backend-guest-wiring.md&amp;lt;/code&amp;gt;] — page-table seams and the guest-memory reachability model.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/04-implementation/01-known-knowns-and-unknowns.md &amp;lt;code&amp;gt;../docs/04-implementation/01-known-knowns-and-unknowns.md&amp;lt;/code&amp;gt;] — server-owned page tables and the IOMMU reachability note.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/05-operations/01-performance-correctness-security.md &amp;lt;code&amp;gt;../docs/05-operations/01-performance-correctness-security.md&amp;lt;/code&amp;gt;] — threat model and the IOMMU rules.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md &amp;lt;code&amp;gt;../debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md&amp;lt;/code&amp;gt;], [https://git.vgpu.io/open-iov.git/tree/debug/risc-v-gsp-rm-vm/docs/44-GMMU-ORACLE-AND-WORKFLOW.md docs/44], [https://git.vgpu.io/open-iov.git/tree/debug/risc-v-gsp-rm-vm/docs/48-GMMU-WALK-AND-LAUNCH-AUDIT.md docs/48] — the field catalogue and the offline walk/audit tooling.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Install_and_First_Run&amp;diff=23982</id>
		<title>Install and First Run</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Install_and_First_Run&amp;diff=23982"/>
		<updated>2026-10-12T04:40:58Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Install and First Run =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' From a fresh Ubuntu host with a supported NVIDIA GPU to a guest VM running a stock NVIDIA driver and &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt;, in about half an hour. Condensed from the maintained guide [https://git.vgpu.io/open-iov.git/tree/docs/02-getting-started/01-install-and-first-run.md &amp;lt;code&amp;gt;../docs/02-getting-started/01-install-and-first-run.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; verified path; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; roadmap item.&lt;br /&gt;
&lt;br /&gt;
== 1. Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
'''Host'''&lt;br /&gt;
&lt;br /&gt;
* Ubuntu 22.04 or 24.04, x86_64 (aarch64 is a &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt;);&lt;br /&gt;
* an NVIDIA GPU covered by the current emulation profile (Turing TU104 is the reference — see [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]]);&lt;br /&gt;
* a working '''host''' NVIDIA driver (&amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; runs on the host; Open-IOV does not modify it);&lt;br /&gt;
* IOMMU enabled (&amp;lt;code&amp;gt;intel_iommu=on&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;amd_iommu=on&amp;lt;/code&amp;gt;), hugepages configured, kernel headers for the running kernel;&lt;br /&gt;
* &amp;lt;code&amp;gt;qemu-system-x86_64&amp;lt;/code&amp;gt; with KVM; libvirt optional;&lt;br /&gt;
* root (or sudo) for module load and mdev creation.&lt;br /&gt;
&lt;br /&gt;
'''Guest'''&lt;br /&gt;
&lt;br /&gt;
* Ubuntu 24.04 server (the reference guest), or any Linux with the matching stock NVIDIA driver available;&lt;br /&gt;
* '''no Open-IOV component at all''' — that is the point ([[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 2. Get the code and build ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;git clone https://git.vgpu.io/open-iov.git&lt;br /&gt;
cd open-iov&lt;br /&gt;
./install.sh deps        # build/runtime dependencies&lt;br /&gt;
./install.sh nvidia      # optional: NVIDIA OpenRM modules + build glue&lt;br /&gt;
./install.sh firmware    # GSP firmware image (verified)&lt;br /&gt;
./install.sh build       # kernel module + userspace&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;install.sh&amp;lt;/code&amp;gt; is safe to re-run. The manual equivalent, and the order that matters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;make kernel                      # first: generates Module.symvers&lt;br /&gt;
./scripts/build_nvidia_openrm.sh # optional (see below)&lt;br /&gt;
make userspace&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Build order matters.''' NVIDIA's OpenRM modules resolve symbols that &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt; exports; building them in the wrong order produces &amp;lt;code&amp;gt;Unknown symbol&amp;lt;/code&amp;gt; failures at load time.&lt;br /&gt;
&lt;br /&gt;
'''The OpenRM stage is optional.''' It is needed only for the native vGPU-management workflows in which NVIDIA's modules are built against the symbols &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt; exports. The QEMU/emulated path uses the distribution driver that already manages the physical GPU; &amp;lt;code&amp;gt;load-stack&amp;lt;/code&amp;gt; skips the OpenRM submodule when a distribution driver is present.&lt;br /&gt;
&lt;br /&gt;
== 3. Load the stack and create a virtual GPU ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;./scripts/stack_manager.sh status        # what is currently loaded&lt;br /&gt;
./scripts/stack_manager.sh load-stack    # vfio/mdev prereqs -&amp;amp;gt; vgsp.ko -&amp;amp;gt; (optional) nvidia&lt;br /&gt;
./scripts/stack_manager.sh mdev-create   # create a vGPU mediated device&lt;br /&gt;
./scripts/stack_manager.sh mdev-list     # inspect /sys/bus/mdev/devices/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The mdev device ''is'' the virtual GPU; everything after this treats it like any other VFIO device.&lt;br /&gt;
&lt;br /&gt;
== 4. Launch a reference guest ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;./scripts/stack_manager.sh qemu          # reference raw-QEMU guest with the mdev&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To integrate with your own stack (libvirt, Xen, ...), attach the mdev exactly as any VFIO device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;amp;lt;hostdev mode='subsystem' type='mdev' model='vfio-pci'&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;source&amp;amp;gt;&lt;br /&gt;
    &amp;amp;lt;address uuid='&amp;amp;lt;mdev-uuid&amp;amp;gt;'/&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;/source&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/hostdev&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Attach behind a root port, not on the root bus.''' QEMU rewrites a device's PCIe capability when it detects a root-complex-integrated endpoint, which changes the link capabilities the guest driver sees. The reference script does this for you.&lt;br /&gt;
&lt;br /&gt;
== 5. Install the stock driver in the guest ==&lt;br /&gt;
&lt;br /&gt;
Inside the guest:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt update&lt;br /&gt;
sudo apt install -y linux-headers-generic build-essential&lt;br /&gt;
# The validated combination is the stock 570.144 Linux runfile (the same&lt;br /&gt;
# driver version as the emulation target).&lt;br /&gt;
sudo sh ./NVIDIA-Linux-x86_64-570.144.run&lt;br /&gt;
sudo reboot&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;nvidia-smi                # must list the virtual GPU&lt;br /&gt;
lsmod | grep -c nvidia&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt; fails to probe, capture host dmesg, guest dmesg, guest &amp;lt;code&amp;gt;lspci -vvv&amp;lt;/code&amp;gt; and the guest module parameters, and file an issue.&lt;br /&gt;
&lt;br /&gt;
== 6. First CUDA check ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# in the guest&lt;br /&gt;
git clone https://github.com/NVIDIA/cuda-samples.git&lt;br /&gt;
cd cuda-samples/Samples/1_Utilities/deviceQuery &amp;amp;amp;&amp;amp;amp; make &amp;amp;amp;&amp;amp;amp; ./deviceQuery&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expectation today''' (&amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; unless noted): driver probe, &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt;, device enumeration and the full CUDA '''driver-API''' smoke complete end to end (&amp;lt;code&amp;gt;ALL OK&amp;lt;/code&amp;gt;, 64-byte payload round-trips). CUDA '''kernel execution''' is the current frontier: a guest launch is forwarded and reaches the engine queue, but engine execution is not yet observed (&amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt;) — see [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] and [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]] before drawing conclusions from a kernel that does not run.&lt;br /&gt;
&lt;br /&gt;
== 7. Day-to-day operations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;./scripts/stack_manager.sh up          # build all + load + create mdev&lt;br /&gt;
./scripts/stack_manager.sh status      # modules, mdev, vfio, firmware&lt;br /&gt;
./scripts/stack_manager.sh test        # host test suite&lt;br /&gt;
./scripts/stack_manager.sh unload      # correct-order teardown&lt;br /&gt;
./scripts/stack_manager.sh cleanup-crash&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Load order is prerequisites → kernel module → (optional) NVIDIA OpenRM → firmware; unload is the reverse. Do not &amp;lt;code&amp;gt;rmmod&amp;lt;/code&amp;gt; by hand while a VM holds the mdev.&lt;br /&gt;
&lt;br /&gt;
== 8. Watching the emulation work ==&lt;br /&gt;
&lt;br /&gt;
The module logs with the prefix '''&amp;lt;code&amp;gt;vgsp-&amp;amp;lt;subsystem&amp;amp;gt;:&amp;lt;/code&amp;gt;''' (for example &amp;lt;code&amp;gt;vgsp-rpc:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;vgsp-sema:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;vgsp-work:&amp;lt;/code&amp;gt;) plus per-RPC traces:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo dmesg -w | grep -i 'vgsp'          # live&lt;br /&gt;
sudo dmesg -T | grep -i 'vgsp' | tail -50&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Developer debug knobs (module parameters) are documented in the repository's debugging workflow document.&lt;br /&gt;
&lt;br /&gt;
== 9. Troubleshooting index ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Symptom&lt;br /&gt;
! Start here&lt;br /&gt;
|-&lt;br /&gt;
| Module will not load&lt;br /&gt;
| &amp;lt;code&amp;gt;dmesg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;modinfo vgsp.ko&amp;lt;/code&amp;gt;, stale module state → &amp;lt;code&amp;gt;cleanup-crash&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| No mdev type for your GPU&lt;br /&gt;
| [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
|-&lt;br /&gt;
| Guest sees wrong PCIe link speed/width&lt;br /&gt;
| attach behind a root port (section 4)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt; probe fails in guest&lt;br /&gt;
| guest dmesg + &amp;lt;code&amp;gt;lspci -vvv&amp;lt;/code&amp;gt; + [[Guest Driver Lifecycle: A Field Guide|&amp;lt;code&amp;gt;Driver-Lifecycle-Field-Guide.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; works, a CUDA kernel does not run&lt;br /&gt;
| expected today — the execution frontier, not your setup ([[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]])&lt;br /&gt;
|-&lt;br /&gt;
| VM boot fails or the guest hangs&lt;br /&gt;
| &amp;lt;code&amp;gt;scripts/stack_manager.sh cleanup-crash&amp;lt;/code&amp;gt;, then reboot&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 10. Uninstall ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;./scripts/stack_manager.sh unload&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The project never modifies your host driver's files; removing the module and its mdev devices returns the host to its previous state.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=The_Host_Module_(vgsp.ko)&amp;diff=23981</id>
		<title>The Host Module (vgsp.ko)</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=The_Host_Module_(vgsp.ko)&amp;diff=23981"/>
		<updated>2026-10-12T04:40:57Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= The Host Module (vgsp.ko) =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' The host-side kernel module that presents one virtual Turing-class GPU per &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; instance: the virtual device, the emulation engine, the guest-memory model and the work-forwarding design. Canonical source: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement with this page.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed with the stock guest driver; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; demonstrated live, being productized; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented default-off behind supervised gates; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; known blocking limit; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; designed, not built; &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; roadmap.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. Role and position ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;guest VM ── PCIe MMIO / DMA / MSI-X through the hypervisor&lt;br /&gt;
   (KVM/QEMU or Xen: VFIO mdev transport, IOMMU)&lt;br /&gt;
   │&lt;br /&gt;
vgsp.ko: virtual device · emulation core · memory model · work path&lt;br /&gt;
   │&lt;br /&gt;
physical GPU + GSP firmware, driven by this module (host driver unmodified)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The module registers as an '''mdev parent''' on the physical GPU, exposing one device type per supported profile; each &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; is an independent virtual GPU ([[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]], [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 2. The virtual device ==&lt;br /&gt;
&lt;br /&gt;
The guest sees a plausible Turing-class GPU (IDs, class code, BARs, capability list). Some fields exist only for validation: PCIe link capabilities (the hypervisor can rewrite them), MSI-X masking state, and non-SR-IOV VF windows.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! BAR&lt;br /&gt;
! Size&lt;br /&gt;
! Backing&lt;br /&gt;
! Contents&lt;br /&gt;
|-&lt;br /&gt;
| BAR0&lt;br /&gt;
| 16 MB&lt;br /&gt;
| host &amp;lt;code&amp;gt;vzalloc&amp;lt;/code&amp;gt; shadow&lt;br /&gt;
| boot, doorbells, VF registers, PRAMIN window, VBIOS&lt;br /&gt;
|-&lt;br /&gt;
| BAR1&lt;br /&gt;
| 256 MB&lt;br /&gt;
| host &amp;lt;code&amp;gt;vzalloc&amp;lt;/code&amp;gt; vidmem buffer&lt;br /&gt;
| guest-visible VRAM aperture&lt;br /&gt;
|-&lt;br /&gt;
| BAR3&lt;br /&gt;
| —&lt;br /&gt;
| instance window&lt;br /&gt;
| instance/PRAMIN behaviour&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
MMIO is served by VFIO region callbacks or directly from the shadow when mapped into the guest. BAR1 is host RAM today — correctness first: the real GPU cannot read it, so forwarding must later migrate objects to real VRAM or expose DMA-mapped system memory [target] ([[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 3. The emulation core ==&lt;br /&gt;
&lt;br /&gt;
A kernel thread drives the device's &amp;quot;firmware&amp;quot; behaviour [live]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BAR0 doorbell / VF-register write → read msgq element from guest memory&lt;br /&gt;
   → dispatch RPC → write reply → inject MSI-X (eventfd → irqfd)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Guest memory is reached via &amp;lt;code&amp;gt;vfio_dma_rw()&amp;lt;/code&amp;gt; from kernel-thread context. The RPC philosophy: correct shape first (or the driver walks off into uninitialized memory), plausible values second (values must be self-consistent), never invent input (in/out parameter blocks are echoed; zeroing the &amp;lt;code&amp;gt;GSP_RM_ALLOC&amp;lt;/code&amp;gt; reply once faulted &amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt;). Handlers cover boot/static-info exchanges, device/FB/BUS/INTR tables, CE and GMMU queries, reserved-PDE contracts, channel/CE allocation and an unknown-control fallback. Push buffers are decoded as method streams and executed in software — memsets, copies, semaphore releases — a '''correctness bridge, not the data plane''' [wip]; emulation-mode CUDA is verified end to end (&amp;lt;code&amp;gt;vectorAdd&amp;lt;/code&amp;gt; over 1M elements, &amp;lt;code&amp;gt;bad=0&amp;lt;/code&amp;gt;) [live]. Physical-GSP boot is default-off [gated]; the firmware analyzer, version tables, HAL tables and dynamic RPC dispatcher are not yet on the live path [target].&lt;br /&gt;
&lt;br /&gt;
== 4. The guest-memory model ==&lt;br /&gt;
&lt;br /&gt;
'''What the client gives us:''' channel memory descriptors (&amp;lt;code&amp;gt;NV_MEMORY_DESC_PARAMS&amp;lt;/code&amp;gt;) with ''physical'' addresses (instance memory, method buffer, userd, ramfc, error notifiers) and the page-table contract for server-owned VA ranges (&amp;lt;code&amp;gt;COPY_SERVER_RESERVED_PDES&amp;lt;/code&amp;gt; — table-level PAs, page shifts, VA range, ''empty'' leaves). It gives us none of its own sysmem maps.&lt;br /&gt;
&lt;br /&gt;
'''What we derive instead''' [live] — the module rebuilds the missing mappings from the guest's own bookkeeping, with no cooperation from the guest driver:&lt;br /&gt;
&lt;br /&gt;
# '''VA↔PA pairs live in guest memory''': UVM and RM record both the GPU VA and the kernel CPU VA per object (&amp;lt;code&amp;gt;uvm_rm_mem_t.vas[CPU]/vas[GPU]&amp;lt;/code&amp;gt; +0x30/+0x38).&lt;br /&gt;
# '''CPU VAs are direct-map addresses''': &amp;lt;code&amp;gt;PA = cpu_va - page_offset_base&amp;lt;/code&amp;gt;, the base recovered from guest memory or &amp;lt;code&amp;gt;/proc/kallsyms&amp;lt;/code&amp;gt; during development.&lt;br /&gt;
# '''Exception:''' control-device &amp;lt;code&amp;gt;mmap()&amp;lt;/code&amp;gt; pages have no leaf PTEs; verified pairs arrive via &amp;lt;code&amp;gt;sema_map_add&amp;lt;/code&amp;gt; until a durable join exists. The page-granular cache is fed by a trusted GMMU walk ([[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
'''Load-bearing copy invariants:''' (1) a copy runs at most once per GPFIFO entry — replays are suppressed by entry-word identity plus an executed-operation bitmap; (2) a virtual operand translates per 4 KB page (195 of 256 pages were contiguous in one observed 1 MB range); (3) a consumed slot's work never runs later — the per-put-epoch mark is authoritative until a put wrap.&lt;br /&gt;
&lt;br /&gt;
== 5. The forwarding path (design) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;guest push submitted&lt;br /&gt;
   → detect (doorbell / GPPUT / push-buffer scan), decode the method stream&lt;br /&gt;
   → EMULATE state/notification (release, membar, fence) or&lt;br /&gt;
     FORWARD real engine work (GR launch, CE copy, memop)&lt;br /&gt;
   → FORWARD: submit equivalent work on a real channel bound to the physical GPU&lt;br /&gt;
   → relay completions (semaphore / fault / interrupt) back into guest memory&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Proxying through the distribution host driver has '''no callable entry point from kernel context''', so the module '''owns the device and runs its real GSP firmware as the resource-manager server''', with emulation as the control plane. CE copies, release and fault relay are implemented default-off and verified live [gated]; GR execution is the open wall [wall] — a forwarded launch reaches the front-end; the inline launch-descriptor install is unobserved ([[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 6. Debug parameters ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/sys/module/vgsp/parameters/*&amp;lt;/code&amp;gt; makes guest memory and the emulated device inspectable without rebuilding:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;scan_guest_ram=&amp;amp;lt;v&amp;amp;gt;&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;scan_vidmem=&amp;amp;lt;v&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| find a 64-bit value in guest RAM (0–8 GB) or the VRAM shadow&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;scan_seq=&amp;amp;lt;v1,...&amp;amp;gt;&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;scan_pt=&amp;amp;lt;pa&amp;amp;gt;&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;scan_masked=&amp;amp;lt;v&amp;amp;gt;,&amp;amp;lt;mask&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| find a 32-bit sequence, entries pointing at a PA, or &amp;lt;code&amp;gt;(x &amp;amp;amp; mask) == v&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dump_vidmem=&amp;amp;lt;off&amp;amp;gt;,&amp;amp;lt;len&amp;amp;gt;&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;fill_vidmem=&amp;amp;lt;v&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| dump/scan or fill the VRAM shadow&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;poke_guest=&amp;amp;lt;gpa&amp;amp;gt;,&amp;amp;lt;v&amp;amp;gt;&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;poke_fill=&amp;amp;lt;gpa&amp;amp;gt;,&amp;amp;lt;v&amp;amp;gt;,&amp;amp;lt;n&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| write a 32-bit value / fill a range in guest physical memory&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sema_probe=&amp;amp;lt;gpu_va&amp;amp;gt;[,count]&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;sema_map_add=&amp;amp;lt;va&amp;amp;gt;,&amp;amp;lt;pa&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| probe a semaphore VA / teach one verified VA→PA pair&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dump_guest=&amp;amp;lt;gpa&amp;amp;gt;,&amp;amp;lt;len&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| dump guest physical memory (capped)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The physical-backend path adds a default-off set of backend controls (documented in the repository; workflows in [https://git.vgpu.io/open-iov.git/tree/docs/05-operations/02-debugging-and-maintenance-workflows.md &amp;lt;code&amp;gt;../docs/05-operations/02-debugging-and-maintenance-workflows.md&amp;lt;/code&amp;gt;]).&lt;br /&gt;
&lt;br /&gt;
== 7. Build and symbol contracts ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt; exports the &amp;lt;code&amp;gt;nvidia_vgpu_vfio_*&amp;lt;/code&amp;gt; interface (&amp;lt;code&amp;gt;probe&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;remove&amp;lt;/code&amp;gt;, ops get/set, mdev parent registration) to pair the device with OpenRM host modules.&lt;br /&gt;
* OpenRM modules built from source need &amp;lt;code&amp;gt;KBUILD_EXTRA_SYMBOLS=$(pwd)/kernel/Module.symvers&amp;lt;/code&amp;gt; and must build '''after''' this module (missing symbols and stale build caches are common otherwise).&lt;br /&gt;
* On single-GPU developer systems the distribution driver owns the physical GPU and the module runs standalone; the OpenRM path is only for native-vGPU management, not QEMU.&lt;br /&gt;
&lt;br /&gt;
== 8. Implemented vs designed ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Area&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| mdev/VFIO device, config space, BARs, MSI-X; BAR0 state machine; boot handshake [live]&lt;br /&gt;
| implemented&lt;br /&gt;
|-&lt;br /&gt;
| Message queues + RPC + init controls (stock 570.144) [live]&lt;br /&gt;
| implemented&lt;br /&gt;
|-&lt;br /&gt;
| Guest sysmem access + VA↔PA discovery [wip]&lt;br /&gt;
| debug-grade, to be productized&lt;br /&gt;
|-&lt;br /&gt;
| Push decoding + semaphore completion [wip]&lt;br /&gt;
| demonstrated live, being productized&lt;br /&gt;
|-&lt;br /&gt;
| Emulation-mode CUDA end-to-end [live]&lt;br /&gt;
| repeatable 1M-element &amp;lt;code&amp;gt;vectorAdd&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bad=0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Guest-RAM physical path + server-owned page-table population [gated]&lt;br /&gt;
| default-off; GPA→HPA via shared-file page cache verified live on the CE&lt;br /&gt;
|-&lt;br /&gt;
| GPU work forwarding: CE copy, release and fault relay [gated]&lt;br /&gt;
| default-off, verified live; GR open [wall]&lt;br /&gt;
|-&lt;br /&gt;
| Execution backend (module-owned GPU, direct real-GSP session) [wall]&lt;br /&gt;
| boot, static configuration and CE copies proven; GR execution open (failed mutating attempts park the device in a locked fail-safe, never auto-retried)&lt;br /&gt;
|-&lt;br /&gt;
| Real VRAM backing [target]; Windows, Xen, aarch64 [planned]&lt;br /&gt;
| designed, not implemented&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 9. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* Canonical chapter: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;] — the source of this condensation.&lt;br /&gt;
* [[GSP RPC Emulation|&amp;lt;code&amp;gt;GSP-RPC-Emulation.md&amp;lt;/code&amp;gt;]], [[BAR Emulation Specification|&amp;lt;code&amp;gt;BAR-Emulation-Specification.md&amp;lt;/code&amp;gt;]], [[WPR Management|&amp;lt;code&amp;gt;WPR-Management.md&amp;lt;/code&amp;gt;]]; [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]], [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]], [[The Guest Stack and CUDASW|&amp;lt;code&amp;gt;Guest-Stack-and-CUDASW.md&amp;lt;/code&amp;gt;]].&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Hardware_and_Software_Matrix&amp;diff=23980</id>
		<title>Hardware and Software Matrix</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Hardware_and_Software_Matrix&amp;diff=23980"/>
		<updated>2026-10-12T04:40:57Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Hardware and Software Matrix =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Companion summary.''' This page condenses [https://git.vgpu.io/open-iov.git/tree/docs/06-portability/hardware-software-matrix.md &amp;lt;code&amp;gt;../docs/06-portability/hardware-software-matrix.md&amp;lt;/code&amp;gt;] — the canonical support matrix: the support ladder, the current status of every host/GPU/guest/hypervisor combination, and what adding a combination requires. The validation process behind every support decision is [https://git.vgpu.io/open-iov.git/tree/docs/06-portability/03-device-validation-and-porting-sequence.md &amp;lt;code&amp;gt;../docs/06-portability/03-device-validation-and-porting-sequence.md&amp;lt;/code&amp;gt;]. When this page and the docs tree disagree, the docs tree wins. Front door: [https://git.vgpu.io/open-iov.git/tree/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[reference]&amp;lt;/code&amp;gt; continuously tested, bugs block releases; &amp;lt;code&amp;gt;[supported]&amp;lt;/code&amp;gt; tested per release; &amp;lt;code&amp;gt;[experimental]&amp;lt;/code&amp;gt; partial or bring-up; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; designed for, bring-up in progress; &amp;lt;code&amp;gt;[design]&amp;lt;/code&amp;gt; design direction, not the current build.&lt;br /&gt;
&lt;br /&gt;
== 1. Support ladder ==&lt;br /&gt;
&lt;br /&gt;
Support means '''tested and documented''', not &amp;quot;should probably work&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Level&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| '''Reference'''&lt;br /&gt;
| continuously tested; bugs block releases&lt;br /&gt;
|-&lt;br /&gt;
| '''Supported'''&lt;br /&gt;
| tested per release; documented workarounds if any&lt;br /&gt;
|-&lt;br /&gt;
| '''Experimental'''&lt;br /&gt;
| known to boot/test partially; may need configuration&lt;br /&gt;
|-&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| architecture designed for it; bring-up in progress&lt;br /&gt;
|-&lt;br /&gt;
| '''Out of scope'''&lt;br /&gt;
| not planned&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 2. Host platforms ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Platform&lt;br /&gt;
! Status&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| x86_64 + NVIDIA Turing (TU104)&lt;br /&gt;
| '''Reference'''&lt;br /&gt;
| the development hardware (RTX 2080-class); the only Reference platform today&lt;br /&gt;
|-&lt;br /&gt;
| x86_64 + Ampere / Ada consumer&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| profile work; expected to be configuration + measurement&lt;br /&gt;
|-&lt;br /&gt;
| x86_64 + Hopper / datacenter&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| requires MIG-aware policy for multi-tenancy&lt;br /&gt;
|-&lt;br /&gt;
| aarch64 + Grace-Hopper (GH200)&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| host-architecture work in the memory model&lt;br /&gt;
|-&lt;br /&gt;
| aarch64 + Grace-Blackwell&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| as above, newer firmware/driver family&lt;br /&gt;
|-&lt;br /&gt;
| GB10 (DGX Spark, Surface-class RTX laptops)&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| same architecture; firmware/ROM quirks to be measured&lt;br /&gt;
|-&lt;br /&gt;
| Other NVIDIA generations&lt;br /&gt;
| '''Experimental'''&lt;br /&gt;
| bring-up path in the canonical document §5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The design direction is that '''each new host platform should require configuration + verification, not new code''' — not the current state: selection is compile-time today and the module is built for the TU104 profile.&lt;br /&gt;
&lt;br /&gt;
== 3. Guest operating systems ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Guest&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| Linux x86_64 (stock &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt;, CUDA)&lt;br /&gt;
| '''Experimental''' — probe, &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; and the driver-API smoke pass; CE-class copies are forwarded default-off; for GR the guest launch reaches the front-end but no grid has dispatched yet (see [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]); no continuous guest testing yet&lt;br /&gt;
|-&lt;br /&gt;
| Linux aarch64&lt;br /&gt;
| '''Target'''&lt;br /&gt;
|-&lt;br /&gt;
| Windows x86_64 (WDDM driver, CUDA, 3D)&lt;br /&gt;
| '''Target'''&lt;br /&gt;
|-&lt;br /&gt;
| Other Unix (FreeBSD, ...)&lt;br /&gt;
| Out of scope until demand&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Guest rule:''' the guest never contains Open-IOV code — no guest agent, no driver patch, no kernel parameters beyond what the stock driver needs.&lt;br /&gt;
&lt;br /&gt;
== 4. Hypervisors and transports ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Hypervisor&lt;br /&gt;
! Status&lt;br /&gt;
! Transport&lt;br /&gt;
|-&lt;br /&gt;
| KVM + QEMU (VFIO mdev)&lt;br /&gt;
| '''Reference'''&lt;br /&gt;
| VFIO mdev + eventfd IRQ + DMA interface&lt;br /&gt;
|-&lt;br /&gt;
| libvirt (mdev attach)&lt;br /&gt;
| '''Supported'''&lt;br /&gt;
| same, via libvirt XML&lt;br /&gt;
|-&lt;br /&gt;
| Zen / KVM on other device models&lt;br /&gt;
| '''Experimental'''&lt;br /&gt;
| as above&lt;br /&gt;
|-&lt;br /&gt;
| Xen (incl. Argo/OpenXT)&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| Xen device model + event channels&lt;br /&gt;
|-&lt;br /&gt;
| Qubes OS / Qubes OS Air&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| compartmentalized VMs; GPU per compartment&lt;br /&gt;
|-&lt;br /&gt;
| Cloud hypervisor / crosvm&lt;br /&gt;
| '''Experimental'''&lt;br /&gt;
| VFIO-based; needs testing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The transport boundary — registration, guest-memory access, interrupt injection — is deliberately narrow, so a new transport is small and isolated.&lt;br /&gt;
&lt;br /&gt;
== 5. What portability means today ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;   host architecture        GPU family            driver/firmware family&lt;br /&gt;
   ┌─────────────────┐   ┌──────────────────┐   ┌────────────────────┐&lt;br /&gt;
   │ x86_64          │   │ Turing (TU104)   │   │ 570.144 (anchor)   │&lt;br /&gt;
   │ aarch64 (Grace) │   │ Ampere / Ada     │   │ newer families     │&lt;br /&gt;
   │ GB10-class      │   │ Hopper / datac.  │   │ (gated, pending    │&lt;br /&gt;
   └────────┬────────┘   └────────┬─────────┘   │  review)           │&lt;br /&gt;
            │                     │             └─────────┬──────────┘&lt;br /&gt;
            └──────────┬──────────┴───────────────────────┘&lt;br /&gt;
                       ▼&lt;br /&gt;
        one combination = hardware profile + version profile&lt;br /&gt;
                       ▼&lt;br /&gt;
        evaluation ladder + evidence  →  matrix entry:&lt;br /&gt;
        &amp;quot;hardware X + driver Y + firmware Z, tested at rung R on date D&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The configuration surface lives in &amp;lt;code&amp;gt;config/&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;config/hardware/&amp;amp;lt;arch&amp;amp;gt;.yaml&amp;lt;/code&amp;gt; (PCI IDs, BARs, memory geometry, engine lists) and &amp;lt;code&amp;gt;config/versions/&amp;amp;lt;driver&amp;amp;gt;.yaml&amp;lt;/code&amp;gt; (RPC/control inventories, capability tables).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''These files are design targets, not live configuration.''' No code reads them today: selection is compile-time and the module is built for the TU104 profile. Treating the YAML surface as authoritative — or claiming &amp;quot;configuration-driven portability&amp;quot; — is aspirational until the profiles are wired into the module's load path. A profile is the ''unit of support''; what is missing is the code that reads the profile files, not the schema.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Adding a new combination ==&lt;br /&gt;
&lt;br /&gt;
'''New GPU / hardware profile.'''&lt;br /&gt;
&lt;br /&gt;
# Create a hardware profile: PCI IDs, BAR layout and sizes, memory geometry (FB size, BAR windows), engine inventory, interrupt topology, and the register values the guest driver validates during probe.&lt;br /&gt;
# Run the five-rung evaluation ladder ([https://git.vgpu.io/open-iov.git/tree/docs/05-operations/01-performance-correctness-security.md &amp;lt;code&amp;gt;../docs/05-operations/01-performance-correctness-security.md&amp;lt;/code&amp;gt;]).&lt;br /&gt;
# Record the differences; prefer configuration over code.&lt;br /&gt;
# Publish the profile, the evidence, and any workarounds.&lt;br /&gt;
&lt;br /&gt;
Firmware-side analysis uses the risc-v-gsp-rm-debugger ([[risc-v-gsp-rm-debugger|&amp;lt;code&amp;gt;Riscv-GSP-RM-Debugger.md&amp;lt;/code&amp;gt;]]): first-touch probes and per-pair comparisons classify each difference as profile data or logic before any profile change lands.&lt;br /&gt;
&lt;br /&gt;
'''New firmware version.''' Images are versioned under &amp;lt;code&amp;gt;firmware/&amp;amp;lt;SERIES&amp;amp;gt;-GSP/&amp;amp;lt;VERSION&amp;amp;gt;/&amp;lt;/code&amp;gt; with signatures and analysis artifacts; the work is capture, inventory diff, decode against that version's reference, then configuration/handlers and a re-run of the ladder.&lt;br /&gt;
&lt;br /&gt;
'''New driver version.''' Run the trace, diff the RPC/control inventory, add version-keyed handlers, re-run the ladder. Newer driver/firmware families are gated pending review before any work starts.&lt;br /&gt;
&lt;br /&gt;
'''Evidence expectations.''' A combination is entered in the matrix only with the profile fields recorded; the firmware/device pairing verified by hash and version string; every first-touch difference explained as profile or logic; per-pair comparison results with session hashes; the metric table with its reference-capture method and stated fidelity limits; and a supervised physical validation for the support claim. &amp;quot;Tested and documented&amp;quot; is literal: an untested or simulator-only combination stays '''Target''' or '''Experimental'''.&lt;br /&gt;
&lt;br /&gt;
== 7. Anchor versions and engine-list portability ==&lt;br /&gt;
&lt;br /&gt;
The anchor is guest CUDA driver (&amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt;) '''570.144''' with GSP firmware '''570.144'''; the host oracle is &amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt; '''570.211.01''' with CUDA toolkit '''12.0'''. The versioned surface is the RM ioctl/class/control interface the userspace driver issues — not a stable public API; see [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
The engine inventory and its class-list filtering are per-architecture, per-driver data. An earlier gap was concrete: a missing async copy engine blocked context creation until the inventory was completed — which is why it belongs in the hardware profile, validated against the host oracle.&lt;br /&gt;
&lt;br /&gt;
== 8. Known portability risks ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Risk&lt;br /&gt;
! Mitigation&lt;br /&gt;
|-&lt;br /&gt;
| Page-size/cache-attribute differences on aarch64&lt;br /&gt;
| keep the memory model abstract; test on Grace early&lt;br /&gt;
|-&lt;br /&gt;
| Windows driver ROM/VBIOS expectations&lt;br /&gt;
| explicit ROM/VBIOS provisioning in the device profile; measured bring-up&lt;br /&gt;
|-&lt;br /&gt;
| Xen interrupt/memory interfaces differ&lt;br /&gt;
| narrow transport interface + Xen backend plan&lt;br /&gt;
|-&lt;br /&gt;
| Vendor ROMs and laptop firmware variants (GB10/Surface)&lt;br /&gt;
| per-device overrides in the profile system&lt;br /&gt;
|-&lt;br /&gt;
| Driver-family drift (580 and newer)&lt;br /&gt;
| version-keyed handlers; matrix-driven testing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 9. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/06-portability/hardware-software-matrix.md &amp;lt;code&amp;gt;../docs/06-portability/hardware-software-matrix.md&amp;lt;/code&amp;gt;] — canonical matrix: ladder, status, procedures; the validation process behind every support claim is in [https://git.vgpu.io/open-iov.git/tree/docs/06-portability/03-device-validation-and-porting-sequence.md &amp;lt;code&amp;gt;../docs/06-portability/03-device-validation-and-porting-sequence.md&amp;lt;/code&amp;gt;].&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/05-operations/01-performance-correctness-security.md &amp;lt;code&amp;gt;../docs/05-operations/01-performance-correctness-security.md&amp;lt;/code&amp;gt;] — the five-rung evaluation ladder and evidence rules.&lt;br /&gt;
* [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] and [[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]] — current status and component map.&lt;br /&gt;
* [[risc-v-gsp-rm-debugger|&amp;lt;code&amp;gt;Riscv-GSP-RM-Debugger.md&amp;lt;/code&amp;gt;]] — firmware-side portability analysis.&lt;br /&gt;
* [[HAAEEP and Collaboration|&amp;lt;code&amp;gt;HAAEEP-and-Collaboration.md&amp;lt;/code&amp;gt;]] — the edge use case and collaboration models.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=HAAEEP_and_Collaboration&amp;diff=23979</id>
		<title>HAAEEP and Collaboration</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=HAAEEP_and_Collaboration&amp;diff=23979"/>
		<updated>2026-10-12T04:40:56Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= HAAEEP and Collaboration =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Companion summary — target architecture.''' This page condenses [https://git.vgpu.io/open-iov.git/tree/docs/08-ecosystem/haaeep-and-collaboration.md &amp;lt;code&amp;gt;../docs/08-ecosystem/haaeep-and-collaboration.md&amp;lt;/code&amp;gt;], the canonical description of the '''High Assurance Agent Edge Environment Platform (HAAEEP)''': a target architecture that Open-IOV exists to enable, and the collaboration models around it. HAAEEP is a proposal and a roadmap, not a shipped product. When this page and the docs tree disagree, the docs tree wins. Front door: [https://git.vgpu.io/open-iov.git/tree/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[proposal]&amp;lt;/code&amp;gt; architecture and roadmap; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; milestone to reach; &amp;lt;code&amp;gt;[goal]&amp;lt;/code&amp;gt; end state; &amp;lt;code&amp;gt;[design]&amp;lt;/code&amp;gt; integration point designed, not built.&lt;br /&gt;
&lt;br /&gt;
== 1. What HAAEEP is ==&lt;br /&gt;
&lt;br /&gt;
An AI agent harness (Claude Code, OpenCode, or any future equivalent) is an untrusted, capability-constrained workload: it runs generated code, holds credentials, and talks to a model. In a ''cloud'' deployment its requests leave the device; in a ''secure edge'' deployment — a workstation, a kiosk, a vehicle, a medical or industrial system — they must not.&lt;br /&gt;
&lt;br /&gt;
HAAEEP is the platform shape for that edge deployment:&lt;br /&gt;
&lt;br /&gt;
* inference runs '''locally''', in its own VM, with the GPU;&lt;br /&gt;
* agents run in '''their own VMs''', without the GPU and without the weights;&lt;br /&gt;
* other functions (desktop, networking, storage) run in '''other VMs''', each isolated;&lt;br /&gt;
* the whole stack is '''attestable''', so remote parties can verify it;&lt;br /&gt;
* and nothing in the design requires the model server, the agent, or the GPU driver to be modified.&lt;br /&gt;
&lt;br /&gt;
Open-IOV is HAAEEP's GPU component. The broader motivation is in [https://git.vgpu.io/open-iov.git/tree/docs/01-orientation/02-the-ai-edge-and-ecosystem.md &amp;lt;code&amp;gt;../docs/01-orientation/02-the-ai-edge-and-ecosystem.md&amp;lt;/code&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
== 2. Architecture ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;┌──────────────────────────────────────────────────────────────────────────┐&lt;br /&gt;
│ EDGE DEVICE — one GPU, local inference only                              │&lt;br /&gt;
│                                                                          │&lt;br /&gt;
│  ┌─────────────────┐     ┌──────────────────┐    ┌───────────────────┐   │&lt;br /&gt;
│  │ Agent VM        │     │ Inference VM     │    │ Infrastructure    │   │&lt;br /&gt;
│  │ capability-     │────▶│ vLLM / SGLang    │    │ desktop, net,     │   │&lt;br /&gt;
│  │ constrained     │ API │ owns GPU via     │    │ storage VMs       │   │&lt;br /&gt;
│  │ no GPU          │     │ Open-IOV mdev or │    │ optional GPU accel│   │&lt;br /&gt;
│  │                 │     │ xen-pci + relay  │    │ via Open-IOV      │   │&lt;br /&gt;
│  └─────────────────┘     └────────┬─────────┘    └───────────────────┘   │&lt;br /&gt;
│                                   │                                      │&lt;br /&gt;
│  ┌────────────────────────────────┴───────────────────────────────────┐  │&lt;br /&gt;
│  │ Hypervisor: KVM / Xen + Argo/OpenXT / Qubes OS Air                 │  │&lt;br /&gt;
│  │  • Flask-XSM / HMX mandatory access control between VMs            │  │&lt;br /&gt;
│  │  • TrenchBoot measured boot: firmware → hypervisor → OS            │  │&lt;br /&gt;
│  │  • Open-IOV: per-VM virtual GPUs, IOMMU-enforced isolation         │  │&lt;br /&gt;
│  └────────────────────────────────────────────────────────────────────┘  │&lt;br /&gt;
└──────────────────────────────────────────────────────────────────────────┘&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Roles and trust ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Component&lt;br /&gt;
! Trust&lt;br /&gt;
! Why&lt;br /&gt;
|-&lt;br /&gt;
| Agent VM&lt;br /&gt;
| untrusted&lt;br /&gt;
| runs generated code; may be compromised&lt;br /&gt;
|-&lt;br /&gt;
| Inference VM&lt;br /&gt;
| high (holds weights)&lt;br /&gt;
| isolated from agents by MAC and by device virtualization&lt;br /&gt;
|-&lt;br /&gt;
| GPU-owning VM (optional)&lt;br /&gt;
| high&lt;br /&gt;
| owns the physical device; can serve others through Open-IOV&lt;br /&gt;
|-&lt;br /&gt;
| Infrastructure VMs&lt;br /&gt;
| medium&lt;br /&gt;
| GPU acceleration optional; no access to weights&lt;br /&gt;
|-&lt;br /&gt;
| Hypervisor&lt;br /&gt;
| TCB&lt;br /&gt;
| enforced by the platform (Argo/OpenXT/Qubes)&lt;br /&gt;
|-&lt;br /&gt;
| Open-IOV device&lt;br /&gt;
| TCB-adjacent&lt;br /&gt;
| must fail closed; audited (see the security doc)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 4. Data flow ==&lt;br /&gt;
&lt;br /&gt;
# An agent VM issues an API call to the inference VM over an internal, MAC-controlled channel.&lt;br /&gt;
# The inference VM's vLLM/SGLang (unchanged) serves the request with the GPU, using its KV-cache plugins (also unchanged).&lt;br /&gt;
# No request ever leaves the device: the platform's network policy forbids external inference endpoints by construction.&lt;br /&gt;
&lt;br /&gt;
'''Optional topology — GPU relay domain.''' Where the platform prefers it (Xen with &amp;lt;code&amp;gt;xen-pci&amp;lt;/code&amp;gt;), one domain owns the physical GPU and relays acceleration to other domains through Open-IOV: the process running the model is isolated from the domain that owns the silicon, and agents are isolated from both.&lt;br /&gt;
&lt;br /&gt;
== 5. Why Open-IOV fits ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Alternative&lt;br /&gt;
! Why it is not enough&lt;br /&gt;
|-&lt;br /&gt;
| Discrete passthrough&lt;br /&gt;
| gives the GPU to exactly one VM; HAAEEP needs the GPU in the inference VM ''and'' optional acceleration elsewhere&lt;br /&gt;
|-&lt;br /&gt;
| Process-level sharing (host CUDA with containers)&lt;br /&gt;
| no VM-level isolation, which is the whole point of the platform&lt;br /&gt;
|-&lt;br /&gt;
| Proprietary vGPU&lt;br /&gt;
| cannot build a sovereign, auditable, redistributable edge platform on a licensed host stack you cannot inspect or modify&lt;br /&gt;
|-&lt;br /&gt;
| Software GPU emulation&lt;br /&gt;
| cannot run models usefully&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Open-IOV is the component in this design that ''must'' be open, permissively licensed and version-durable — so it is the component we are building. Its isolation model is described in [[GMMU Multi-Tenant Protection|&amp;lt;code&amp;gt;GMMU-Multi-Tenant-Protection.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
== 6. Roadmap (proposal) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Milestone&lt;br /&gt;
! Depends on&lt;br /&gt;
|-&lt;br /&gt;
| CUDA execution in a guest (rung 3)&lt;br /&gt;
| rung 2 (runtime start) is green; CE-class work is forwarded with release and fault relay in place (default off); for GR the guest launch reaches the front-end but no grid has dispatched yet — the frontier is tracked in [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
|-&lt;br /&gt;
| Two-VM coexistence (inference + agent) with isolation&lt;br /&gt;
| Open-IOV multi-tenancy + platform MAC&lt;br /&gt;
|-&lt;br /&gt;
| Xen/OpenXT or Qubes Air variant&lt;br /&gt;
| Open-IOV transport backends&lt;br /&gt;
|-&lt;br /&gt;
| Attested boot-to-inference chain&lt;br /&gt;
| TrenchBoot integration&lt;br /&gt;
|-&lt;br /&gt;
| Published reference platform (scripts, docs)&lt;br /&gt;
| all of the above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each milestone is documented as it lands, with the same evidence discipline as the rest of the project. Nothing in this table is claimed today: it is the proposal.&lt;br /&gt;
&lt;br /&gt;
== 7. Collaboration models ==&lt;br /&gt;
&lt;br /&gt;
'''Open source projects.''' Adopt the code under BSD-3-Clause (kernel modules are GPL-2.0 — see [https://git.vgpu.io/open-iov.git/tree/docs/09-reference/legal-and-licensing.md &amp;lt;code&amp;gt;../docs/09-reference/legal-and-licensing.md&amp;lt;/code&amp;gt;]). We treat interface requirements as design inputs (transports, IRQ models, memory interfaces), provide the transport abstraction rather than asking for forks, and test against partner platforms in the matrix.&lt;br /&gt;
&lt;br /&gt;
'''Commercial partners.''' Welcome, with no license fee: ship Open-IOV in products and differentiate above it; sponsor support for specific hardware/driver versions; co-develop under the same permissive terms.&lt;br /&gt;
&lt;br /&gt;
'''Hardware vendors.''' Nothing is required. The goal is that new hardware works through configuration and measurement; if you want to accelerate support, share hardware and traces, and we publish what we learn.&lt;br /&gt;
&lt;br /&gt;
'''Security researchers.''' The emulation's attack surface is small and documented. Break it. Findings and fixes are published, with credit.&lt;br /&gt;
&lt;br /&gt;
== 8. Cross-project notes ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Project&lt;br /&gt;
! Relationship&lt;br /&gt;
|-&lt;br /&gt;
| '''Qubes OS Air'''&lt;br /&gt;
| compartmentalization on modern hardware; Open-IOV makes GPU acceleration usable per compartment (especially AI workloads)&lt;br /&gt;
|-&lt;br /&gt;
| '''TrenchBoot'''&lt;br /&gt;
| measured/attested boot; combined, the platform can attest the inference path&lt;br /&gt;
|-&lt;br /&gt;
| '''Argo / OpenXT'''&lt;br /&gt;
| hypervisor-mediated exchange (HMX) and Flask-XSM MAC; Open-IOV respects and complements that policy&lt;br /&gt;
|-&lt;br /&gt;
| '''KVM/VFIO gaming'''&lt;br /&gt;
| established the fast-passthrough pattern; Open-IOV serves users who need ''multiple'' VMs or cannot dedicate the GPU&lt;br /&gt;
|-&lt;br /&gt;
| '''vLLM / SGLang'''&lt;br /&gt;
| remain the inference answer; Open-IOV isolates them without changing them; KV-cache plugins keep working&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 9. How to help ==&lt;br /&gt;
&lt;br /&gt;
* '''Platform builders''': bring your hypervisor; tell us the transport you need.&lt;br /&gt;
* '''Security engineers''': review the isolation model and the debug surface.&lt;br /&gt;
* '''AI-infrastructure engineers''': define the reference HAAEEP deployment with us (model server, KV cache, agent harness).&lt;br /&gt;
* '''Everyone''': run the evaluation ladder on your hardware and send the evidence.&lt;br /&gt;
&lt;br /&gt;
Contact and participation channels are in [https://git.vgpu.io/open-iov.git/tree/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;] §6 &amp;quot;How to get involved&amp;quot;. We would rather have a hundred partners than a hundred forks.&lt;br /&gt;
&lt;br /&gt;
== 10. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/08-ecosystem/haaeep-and-collaboration.md &amp;lt;code&amp;gt;../docs/08-ecosystem/haaeep-and-collaboration.md&amp;lt;/code&amp;gt;] — canonical HAAEEP architecture, roadmap and collaboration models.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/01-orientation/02-the-ai-edge-and-ecosystem.md &amp;lt;code&amp;gt;../docs/01-orientation/02-the-ai-edge-and-ecosystem.md&amp;lt;/code&amp;gt;] — the AI-edge motivation and ecosystem stance.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/05-operations/01-performance-correctness-security.md &amp;lt;code&amp;gt;../docs/05-operations/01-performance-correctness-security.md&amp;lt;/code&amp;gt;] — the evaluation ladder behind every milestone.&lt;br /&gt;
* [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] and [[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]] — current status and component map.&lt;br /&gt;
* [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]] and [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]] — the GR frontier and how work reaches real hardware.&lt;br /&gt;
* [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]] — what runs where, and how support is added.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=The_Guest_Stack_and_CUDASW&amp;diff=23978</id>
		<title>The Guest Stack and CUDASW</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=The_Guest_Stack_and_CUDASW&amp;diff=23978"/>
		<updated>2026-10-12T04:40:56Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= The Guest Stack and CUDASW =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' What runs inside the guest, how the NVIDIA software layers sit on top of the device, and what the unmodified guest driver expects from the emulated GPU. Canonical source: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/02-guest-stack-and-cudasw.md &amp;lt;code&amp;gt;../docs/03-architecture/02-guest-stack-and-cudasw.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement with this page.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed with the stock guest driver; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented default-off behind supervised gates; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; known blocking limit; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; designed, not built; &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; roadmap.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. Vocabulary: what &amp;quot;CUDASW&amp;quot; means here ==&lt;br /&gt;
&lt;br /&gt;
'''CUDASW''' is the family of NVIDIA ''software'' components that sit between an application and the GPU driver. The project's compatibility target is the whole stack, not one library:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;application&lt;br /&gt;
   │  CUDA API (runtime)&lt;br /&gt;
libcudart.so ─────────────────────────────┐  runtime: device/stream/event&lt;br /&gt;
   │  CUDA driver API                    │  management, kernel launch&lt;br /&gt;
libcuda.so ───────────────────────────────┤  driver: contexts, modules,&lt;br /&gt;
   │  ioctls                             │  memory, channel submission&lt;br /&gt;
/dev/nvidia* ─────────────────────────────┘&lt;br /&gt;
nvidia.ko (RM + UVM + modeset)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Adjacent members of the family: '''libnvidia-ptxjitcompiler''' (PTX→SASS JIT — usually &amp;quot;just works&amp;quot; once the driver initializes), '''libnvidia-fatbinaryloader / nvrtc''', '''UVM''' (&amp;lt;code&amp;gt;nvidia_uvm.ko&amp;lt;/code&amp;gt; — [[UVM in the Guest|&amp;lt;code&amp;gt;UVM-in-the-Guest.md&amp;lt;/code&amp;gt;]]), the '''graphics stack''' (&amp;lt;code&amp;gt;libGLX_nvidia&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;libnvidia-glcore&amp;lt;/code&amp;gt;, Vulkan ICD, &amp;lt;code&amp;gt;nvidia_modeset&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;nvidia_drm&amp;lt;/code&amp;gt;) and the '''video stack''' (NVENC/NVDEC) — both roadmapped.&lt;br /&gt;
&lt;br /&gt;
== 2. Layering rules the emulation must respect ==&lt;br /&gt;
&lt;br /&gt;
# '''The kernel driver is the contract.''' Everything above it talks to &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt; through stable ioctls, memory mappings and &amp;lt;code&amp;gt;/dev/nvidia*&amp;lt;/code&amp;gt; nodes. If the kernel driver initializes and behaves, user space follows.&lt;br /&gt;
# '''User space is opaque to us.''' We never intercept user-space APIs. All hooks are in the device model (host side) or in the ''hardware interface'' the kernel driver sees (guest side).&lt;br /&gt;
# '''Version skew is normal.''' Driver version, CUDA version and firmware version are three independent axes. The compatibility target is &amp;quot;the driver family that matches the emulated firmware profile&amp;quot;, with configuration-driven adaptation for others.&lt;br /&gt;
&lt;br /&gt;
== 3. Kernel-driver anatomy (what the guest brings) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Component&lt;br /&gt;
! Role&lt;br /&gt;
! Why it matters here&lt;br /&gt;
|-&lt;br /&gt;
| RM core&lt;br /&gt;
| object model, handles, locks, device lifecycle&lt;br /&gt;
| drives the GSP boot and the whole RPC/control surface&lt;br /&gt;
|-&lt;br /&gt;
| Resource server (&amp;lt;code&amp;gt;resserv&amp;lt;/code&amp;gt;)&lt;br /&gt;
| allocates/tracks objects, memory, channels&lt;br /&gt;
| the client half of the client/server RM split&lt;br /&gt;
|-&lt;br /&gt;
| Memory manager (&amp;lt;code&amp;gt;memmgr&amp;lt;/code&amp;gt;)&lt;br /&gt;
| VRAM/sysmem objects, mappings, page tables&lt;br /&gt;
| the guest expects the GSP to own page-table leaves for its VA spaces&lt;br /&gt;
|-&lt;br /&gt;
| FIFO/runlist&lt;br /&gt;
| channels, TSGs, GPFIFO, USERD, doorbells&lt;br /&gt;
| where the guest's work is submitted&lt;br /&gt;
|-&lt;br /&gt;
| GSP client&lt;br /&gt;
| message queues, RPC transport, event handling&lt;br /&gt;
| the interface we emulate&lt;br /&gt;
|-&lt;br /&gt;
| UVM&lt;br /&gt;
| unified memory, page faults, channel manager&lt;br /&gt;
| starts early in CUDA init, extremely stateful&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nvidia_modeset&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;nvidia_drm&amp;lt;/code&amp;gt;&lt;br /&gt;
| display / DRM&lt;br /&gt;
| needed later for graphics&lt;br /&gt;
|-&lt;br /&gt;
| CE / GR HALs&lt;br /&gt;
| engine programming&lt;br /&gt;
| needed to ''execute'' forwarded work&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 4. Driver initialization vs runtime ==&lt;br /&gt;
&lt;br /&gt;
Understanding this split is the key to debugging.&lt;br /&gt;
&lt;br /&gt;
'''Initialization (boot/probe)''' — deterministic, mostly one-shot; where compatibility is won or lost [live]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;PCI probe → identify GPU from config space and BAR0 registers&lt;br /&gt;
   → boot the GSP (our emulated handshake)&lt;br /&gt;
   → read static configuration (device info tables, FB/BUS info, VBIOS, clocks)&lt;br /&gt;
   → create root client/device/subdevice objects&lt;br /&gt;
   → initialize RM subsystems (interrupts, FIFO, memory, GMMU, PMU)&lt;br /&gt;
   → expose /dev/nvidia* and register with the kernel&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The actual message/control IDs observed at each step are listed in [[Guest Driver Lifecycle: A Field Guide|&amp;lt;code&amp;gt;Driver-Lifecycle-Field-Guide.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
'''Runtime (per-process, per-context)''' — driven by user-space workloads; where ''execution'' is won or lost:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;open /dev/nvidia* → cuInit → UVM registration (per process)&lt;br /&gt;
   → cuCtxCreate → object/allocations → memory maps&lt;br /&gt;
   → channel creation + push buffers + semaphores&lt;br /&gt;
   → kernel launches (GR) / copies (CE) / memops&lt;br /&gt;
   → faults, completions, events&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Context creation and the full CUDA driver-API smoke now pass (&amp;lt;code&amp;gt;ALL OK&amp;lt;/code&amp;gt;, copies matched) [live]. The current focus is execution: the backend is a '''module-owned GPU running its real GSP firmware as the resource-manager server''' ([[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]]), with CE-class copies forwarded to the physical copy engine default-off [gated]. For GR, a forwarded guest launch reaches the front-end but the inline launch-descriptor install has not been observed — the open execution wall ([[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]) [wall].&lt;br /&gt;
&lt;br /&gt;
== 5. What the guest expects from the device, per phase ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Phase&lt;br /&gt;
! Guest action&lt;br /&gt;
! Device/firmware expectation&lt;br /&gt;
|-&lt;br /&gt;
| Probe&lt;br /&gt;
| config space reads, BAR sizing, MSI-X capability&lt;br /&gt;
| a plausible TU104-family PCIe GPU&lt;br /&gt;
|-&lt;br /&gt;
| Boot&lt;br /&gt;
| BAR0 register writes, WPR setup, firmware boot sequence&lt;br /&gt;
| GSP boots, booter completes, &amp;quot;GSP init done&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Config&lt;br /&gt;
| RPC &amp;lt;code&amp;gt;GET_GSP_STATIC_INFO&amp;lt;/code&amp;gt;, device tables, VBIOS reads&lt;br /&gt;
| consistent, self-describing tables&lt;br /&gt;
|-&lt;br /&gt;
| RM init&lt;br /&gt;
| &amp;lt;code&amp;gt;GSP_RM_CONTROL&amp;lt;/code&amp;gt; battery (FB/BUS/CE/INTR/GMMU/...)&lt;br /&gt;
| correct shapes and plausible values&lt;br /&gt;
|-&lt;br /&gt;
| Objects&lt;br /&gt;
| &amp;lt;code&amp;gt;GSP_RM_ALLOC&amp;lt;/code&amp;gt; (root, device, subdevice, vaspace, channel, CE objects)&lt;br /&gt;
| success + correct handles/params&lt;br /&gt;
|-&lt;br /&gt;
| Runtime&lt;br /&gt;
| allocs/controls for maps and channels; pushes&lt;br /&gt;
| executed work, semaphores, faults&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The RPC surface is described in [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]] and [[RPC Message Format|&amp;lt;code&amp;gt;RPC-Message-Format.md&amp;lt;/code&amp;gt;]]; the boot handshake in [[WPR Management|&amp;lt;code&amp;gt;WPR-Management.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
== 6. Why user-space-only interception does not work ==&lt;br /&gt;
&lt;br /&gt;
Two hard-won facts from this project:&lt;br /&gt;
&lt;br /&gt;
# '''&amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt; issues raw &amp;lt;code&amp;gt;syscall&amp;lt;/code&amp;gt; instructions''', so an &amp;lt;code&amp;gt;LD_PRELOAD&amp;lt;/code&amp;gt; shim around &amp;lt;code&amp;gt;ioctl()&amp;lt;/code&amp;gt; sees nothing. Observing CUDA's kernel calls requires a &amp;lt;code&amp;gt;ptrace&amp;lt;/code&amp;gt;-based tracer (PTRACE_SYSCALL + PTRACE_GET_SYSCALL_INFO), as the project's diagnostics do.&lt;br /&gt;
# **The CUDA driver talks to the ''kernel driver'', not to the device.** All device interaction happens in &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt;. This is good news: the emulation boundary is a small set of kernel-side interfaces (MMIO, DMA, interrupts, the GSP protocol) rather than a large user-space API surface.&lt;br /&gt;
&lt;br /&gt;
== 7. Windows guests ==&lt;br /&gt;
&lt;br /&gt;
Windows brings its own kernel-mode driver, &amp;lt;code&amp;gt;nvlddmkm.sys&amp;lt;/code&amp;gt;, which uses the same underlying GSP device/firmware model but different host interfaces (WDDM, MSI-X semantics, ROM/VBIOS quirks). The emulation target is the same: satisfy the firmware interface, forward the work. Windows support is a roadmap item ([[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]]) [planned], and the design goal is that no Windows-specific code lives in the guest.&lt;br /&gt;
&lt;br /&gt;
== 8. Compatibility notes for versions ==&lt;br /&gt;
&lt;br /&gt;
* The guest's driver and the emulated firmware profile must agree on the RPC message versions. The guest negotiates these at start-up (&amp;lt;code&amp;gt;SET_GUEST_SYSTEM_INFO&amp;lt;/code&amp;gt; carries the VGX/RPC version); the emulation answers with a profile that matches the driver family in use.&lt;br /&gt;
* CUDA versions ride on driver versions; the test matrix tracks (driver, CUDA, firmware) triples ([https://git.vgpu.io/open-iov.git/tree/docs/05-operations/01-performance-correctness-security.md &amp;lt;code&amp;gt;../docs/05-operations/01-performance-correctness-security.md&amp;lt;/code&amp;gt;]).&lt;br /&gt;
&lt;br /&gt;
== 9. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/02-guest-stack-and-cudasw.md &amp;lt;code&amp;gt;../docs/03-architecture/02-guest-stack-and-cudasw.md&amp;lt;/code&amp;gt;] — canonical chapter.&lt;br /&gt;
* [[The Host Module (vgsp.ko)|&amp;lt;code&amp;gt;Host-Module.md&amp;lt;/code&amp;gt;]] — the other side of the boundary.&lt;br /&gt;
* [[UVM in the Guest|&amp;lt;code&amp;gt;UVM-in-the-Guest.md&amp;lt;/code&amp;gt;]], [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]] — user-space driver internals.&lt;br /&gt;
* [[Guest Driver Lifecycle: A Field Guide|&amp;lt;code&amp;gt;Driver-Lifecycle-Field-Guide.md&amp;lt;/code&amp;gt;]], [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]] — the observed protocol reality.&lt;br /&gt;
* [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]], [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]] — where guest work is headed.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=GSP_and_GSP-RM&amp;diff=23977</id>
		<title>GSP and GSP-RM</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=GSP_and_GSP-RM&amp;diff=23977"/>
		<updated>2026-10-12T04:40:55Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= GSP and GSP-RM =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' The GPU System Processor hosts NVIDIA's Resource Manager in firmware; since Turing, the guest driver's management path is ''talking to that firmware'', not to silicon. This page explains that architecture and the interface the project emulates. Condensed from [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/03-gsp-and-gsp-rm.md &amp;lt;code&amp;gt;../docs/03-architecture/03-gsp-and-gsp-rm.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; proven with the stock guest driver; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partial; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; current blocker; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; designed end state.&lt;br /&gt;
&lt;br /&gt;
== 1. What the GSP is ==&lt;br /&gt;
&lt;br /&gt;
The '''GSP''' is a small embedded RISC-V processor (RV64IMAC) inside NVIDIA GPUs. It runs a firmware image (for the 570.144 generation, a ~28 MB ELF) that contains, among other things, a full port of NVIDIA's '''Resource Manager (RM)''' — the component that owns GPU initialization, memory, engines, interrupts and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;   ┌──────────────────────────── GUEST ────────────────────────────┐&lt;br /&gt;
   │  nvidia.ko                                                   │&lt;br /&gt;
   │    RM client path ── RPC ──┐                                  │&lt;br /&gt;
   │    GSP boot code           │                                  │&lt;br /&gt;
   └────────────────────────────┼──────────────────────────────────┘&lt;br /&gt;
                                │  shared memory queues + doorbells&lt;br /&gt;
   ┌────────────────────────────┼──────────────────────────────────┐&lt;br /&gt;
   │  GSP (firmware, RISC-V)    │                                   │&lt;br /&gt;
   │    RM core (RMCore)  ◄─────┘                                   │&lt;br /&gt;
   │    RM API  (object model, clients, handles)                    │&lt;br /&gt;
   │    Resource server (resserv): allocation &amp;amp;amp; lifetime            │&lt;br /&gt;
   │    memory manager, GMMU, FIFO/runlist, interrupts, PMU         │&lt;br /&gt;
   └───────────────────────────────────────────────────────────────┘&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A driver as complex as NVIDIA's is not written to program silicon directly; it is written to talk to an RM, and on modern GPUs a copy of the RM runs on the GSP. The driver is therefore an '''RM client''': it issues requests, receives callbacks, and observes state through a well-defined protocol.&lt;br /&gt;
&lt;br /&gt;
== 2. The boot handshake we emulate ==&lt;br /&gt;
&lt;br /&gt;
The guest driver boots the GSP exactly as it would on bare metal:&lt;br /&gt;
&lt;br /&gt;
# '''WPR setup''' — carve a firmware-protected region of VRAM and write descriptors into BAR0 registers ([[WPR Management|&amp;lt;code&amp;gt;WPR-Management.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
# '''FWSEC''' — the driver verifies firmware signatures.&lt;br /&gt;
# '''Booter''' — the boot ROM consumes the firmware image.&lt;br /&gt;
# '''RISCV start''' — the RISC-V core begins executing the firmware.&lt;br /&gt;
# '''GSP init done''' — the firmware signals readiness through a status mailbox; the driver proceeds to initialization RPCs.&lt;br /&gt;
&lt;br /&gt;
The emulation implements '''stage completion''' rather than the stages themselves — legitimate because the only observable to the driver is the state machine it polls. The same handshake has also been run against real firmware on the physical backend: the firmware comes up, delivers its first status events, serves the static configuration, and stays live until the unload RPC releases it ([[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 3. The transport: message queues and RPC ==&lt;br /&gt;
&lt;br /&gt;
GSP-RM's transport is a shared-memory message queue pair:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  guest system memory (allocated by the guest driver, registered with us)&lt;br /&gt;
  ┌───────────────────────────────┐&lt;br /&gt;
  │ command queue (guest -&amp;amp;gt; GSP)  │  element ring, 4 KB elements&lt;br /&gt;
  ├───────────────────────────────┤&lt;br /&gt;
  │ status queue  (GSP -&amp;amp;gt; guest)  │  element ring&lt;br /&gt;
  └───────────────────────────────┘&lt;br /&gt;
     + a page table describing the queue pages (the buffer is&lt;br /&gt;
       non-contiguous: each page is an independent allocation)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each element begins with a transport header followed by an '''RPC message''' whose 32-byte header carries header version, length, function, result and sequence number. Observations worth knowing (all verified against the stock guest):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; covers the fixed part of the message, not variable payloads — do not use it to bound a payload;&lt;br /&gt;
* function numbers are a flat enum shared by several protocols (&amp;lt;code&amp;gt;SET_GUEST_SYSTEM_INFO&amp;lt;/code&amp;gt; 1, &amp;lt;code&amp;gt;FREE&amp;lt;/code&amp;gt; 10, &amp;lt;code&amp;gt;GET_GSP_STATIC_INFO&amp;lt;/code&amp;gt; 65, &amp;lt;code&amp;gt;GSP_RM_CONTROL&amp;lt;/code&amp;gt; 76, &amp;lt;code&amp;gt;GSP_RM_ALLOC&amp;lt;/code&amp;gt; 103, ...);&lt;br /&gt;
* replies must be matched to request sequence numbers — the driver runs a reply-matching state machine, and a slow reply is indistinguishable from a hang.&lt;br /&gt;
&lt;br /&gt;
== 4. RMCore, the RM API and the resource server ==&lt;br /&gt;
&lt;br /&gt;
Three RM concepts make every log readable:&lt;br /&gt;
&lt;br /&gt;
* '''RMCore''' — the object system. Everything is an object with a class (a 32-bit class ID), a handle in a per-client handle space, and a parent object forming a tree rooted at a client. Traces of &amp;lt;code&amp;gt;GSP_RM_ALLOC&amp;lt;/code&amp;gt; are object creation; traces of &amp;lt;code&amp;gt;GSP_RM_CONTROL&amp;lt;/code&amp;gt; are method calls on objects.&lt;br /&gt;
* '''RM API''' — how in-kernel components (and user space via ioctls) allocate objects and call controls, with an implicit-handle and an explicit-handle variant. For a GSP client, part of the API becomes RPCs while some calls are handled locally; memory objects, for example, are allocated locally by the client RM.&lt;br /&gt;
* '''Resource server (resserv)''' — the allocation authority: it owns handle spaces, enforces privileges and tracks object lifetimes.&lt;br /&gt;
&lt;br /&gt;
== 5. The client/server split (and why page tables matter) ==&lt;br /&gt;
&lt;br /&gt;
Modern RM is client/server: the '''client''' (guest &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt;) owns per-process state and submits work; the '''server''' (GSP-RM) owns GPU-global state — routing, page tables, scheduling domains, engine configuration. For virtualized setups the client tells the server which VA ranges the server owns, and the server manages the deeper page-table levels for those ranges. The client hands over the '''physical addresses of its page-table levels''' plus the VA ranges they cover; on real hardware the server then fills in the lower levels for server-owned ranges and the client never writes them.&lt;br /&gt;
&lt;br /&gt;
This is a central fact for the execution work: when the guest's UVM asks the &amp;quot;GPU&amp;quot; to map memory, the mapping is expected to materialize in page tables that only the server side can write — which is us ([[UVM in the Guest|&amp;lt;code&amp;gt;UVM-in-the-Guest.md&amp;lt;/code&amp;gt;]], [[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 6. Event channels and notifications ==&lt;br /&gt;
&lt;br /&gt;
Beyond request/reply, the guest needs asynchronous events: event objects registered with a notification configuration (an MSI-X vector or a memory &amp;quot;semaphore&amp;quot; the GPU can write), completion events when channels finish work or errors occur, delivered as a strict bit/handle/state triple on the exact vector. The emulation's MSI-X path is emulation thread → &amp;lt;code&amp;gt;eventfd&amp;lt;/code&amp;gt; → KVM → guest vector, with the pending-bit array emulated so a masked vector's interrupt is not lost.&lt;br /&gt;
&lt;br /&gt;
== 7. What we emulate today ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Layer&lt;br /&gt;
! State&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GSP boot state machine&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
| stages complete; the driver's poll loop is satisfied&lt;br /&gt;
|-&lt;br /&gt;
| Message queue transport&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
| including the non-contiguous page table for the queue buffer&lt;br /&gt;
|-&lt;br /&gt;
| RPC request/reply&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
| every function the driver uses during init is answered; unknown functions get a well-formed success reply&lt;br /&gt;
|-&lt;br /&gt;
| Static info tables&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
| device/FB/BUS/INTR/GMMU tables carry plausible reference values; the engine inventory is complete and agrees with the class list&lt;br /&gt;
|-&lt;br /&gt;
| Controls during init&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
| ~160 distinct control IDs observed per CUDA run; a small set is special-cased with real values and reply fidelity for the consumed fields keeps improving&lt;br /&gt;
|-&lt;br /&gt;
| Object creation&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
| handles/parameters are echoed consistently (zeroing the request parameters corrupts the caller); there is no server-side object model yet&lt;br /&gt;
|-&lt;br /&gt;
| Page tables for server-owned ranges&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
| contract received and recorded; leaf population is the execution work&lt;br /&gt;
|-&lt;br /&gt;
| Event/notification delivery&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
| MSI-X works; richer event semantics land with forwarding&lt;br /&gt;
|-&lt;br /&gt;
| Firmware behaviour (routing, scheduling, real execution)&lt;br /&gt;
| &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt;&lt;br /&gt;
| the execution frontier — see [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 8. Where the firmware knowledge lives ==&lt;br /&gt;
&lt;br /&gt;
* [[GSP 570.144W Firmware Analysis|&amp;lt;code&amp;gt;GSP-570.144W-Firmware-Analysis.md&amp;lt;/code&amp;gt;]] — how the 28.5 MB image was decompiled and mapped.&lt;br /&gt;
* [[Address Reference|&amp;lt;code&amp;gt;Address-Reference.md&amp;lt;/code&amp;gt;]] — firmware-side address tables.&lt;br /&gt;
* [[RPC Message Format|&amp;lt;code&amp;gt;RPC-Message-Format.md&amp;lt;/code&amp;gt;]], [[GSP RPC Emulation|&amp;lt;code&amp;gt;GSP-RPC-Emulation.md&amp;lt;/code&amp;gt;]] — historical RPC analysis (superseded; kept for the record).&lt;br /&gt;
* [[WPR Management|&amp;lt;code&amp;gt;WPR-Management.md&amp;lt;/code&amp;gt;]] — write-protected region semantics.&lt;br /&gt;
* [[The vGSP Execution Plane (vEP)|The execution plane]] and [[The Execution Frontier|the execution frontier]] — what turns this protocol into real work on real hardware.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=MediaWiki:Sidebar&amp;diff=23976</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=MediaWiki:Sidebar&amp;diff=23976"/>
		<updated>2026-10-12T04:40:28Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links to the cgit tree/repo URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** Project Status&lt;br /&gt;
** Documentation&lt;br /&gt;
** FAQ&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
* Deep dives&lt;br /&gt;
** System Overview&lt;br /&gt;
** GSP and GSP-RM&lt;br /&gt;
** The vGSP Execution Plane (vEP)&lt;br /&gt;
** The Host Module (vgsp.ko)&lt;br /&gt;
** The Guest Stack and CUDASW&lt;br /&gt;
** CUDA Userspace Driver&lt;br /&gt;
** Introduction to GMMU&lt;br /&gt;
** UVM in the Guest&lt;br /&gt;
** Physical GPU Backend and Guest Wiring&lt;br /&gt;
** The Execution Frontier&lt;br /&gt;
* Project&lt;br /&gt;
** Open-IOV:About|About Open-IOV&lt;br /&gt;
** Install and First Run&lt;br /&gt;
** Hardware and Software Matrix&lt;br /&gt;
** HAAEEP and Collaboration&lt;br /&gt;
** risc-v-gsp-rm-debugger&lt;br /&gt;
** Glossary&lt;br /&gt;
* Community&lt;br /&gt;
** Community&lt;br /&gt;
** https://git.vgpu.io/open-iov.git/|Source repository&lt;br /&gt;
** https://discord.gg/Rb9K9DYxKK|Discord&lt;br /&gt;
* SEARCH&lt;br /&gt;
* TOOLBOX&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Community&amp;diff=23975</id>
		<title>Community</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Community&amp;diff=23975"/>
		<updated>2026-10-12T04:40:27Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links to the cgit tree/repo URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
'''Chat:''' [https://discord.gg/Rb9K9DYxKK Open-IOV Discord]&lt;br /&gt;
&lt;br /&gt;
'''Source code and issues:''' [https://git.vgpu.io/open-iov.git/ git.vgpu.io/open-iov]&lt;br /&gt;
&lt;br /&gt;
== Contributing ==&lt;br /&gt;
The project welcomes contributors of every kind. The most valuable contribution is evidence: a new hardware or software combination tested with the project's methodology, with the captures listed in the repository's debugging document.&lt;br /&gt;
&lt;br /&gt;
* Start from [[Hardware and Software Matrix]] to see which combinations are Reference, Target or Experimental.&lt;br /&gt;
* The repository's developer onboarding document describes the environment, the coding standards and how a change is landed.&lt;br /&gt;
* For the firmware side, [[risc-v-gsp-rm-debugger]] is the host-side workbench; the tool documentation is in the repository.&lt;br /&gt;
&lt;br /&gt;
'''Editorial policy for this wiki:''' account creation and editing are closed to prevent spam. The wiki is maintained from the project's tracked documentation by the project's publishing bot; corrections and additions are made through the repository.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Documentation&amp;diff=23974</id>
		<title>Documentation</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Documentation&amp;diff=23974"/>
		<updated>2026-10-12T04:40:25Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links to the cgit tree/repo URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
This is the index of the Open-IOV wiki. If you are new, read '''[[Project Status]]''' first, then '''[[System Overview]]'''. The wiki is a curated public view of the project's maintained documentation; each page names its canonical document in the [https://git.vgpu.io/open-iov.git/ repository].&lt;br /&gt;
&lt;br /&gt;
== Start here ==&lt;br /&gt;
* [[Project Status]] — what works today, what is in progress, what is not started&lt;br /&gt;
* [[Install and First Run]] — build, load, and a stock guest driver in about half an hour&lt;br /&gt;
* [[System Overview]] — the architecture in one page&lt;br /&gt;
* [[FAQ]] — common questions, including &amp;quot;why is nvidia-smi working but CUDA not?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
* [[System Overview]] — principle, layer map, data flows&lt;br /&gt;
* [[GSP and GSP-RM]] — the firmware interface the project emulates&lt;br /&gt;
* [[The Host Module (vgsp.ko)]] — virtual device, emulation core, memory model, forwarding&lt;br /&gt;
* [[The Guest Stack and CUDASW]] — what runs unmodified inside the guest&lt;br /&gt;
* [[The vGSP Execution Plane (vEP)]] — the execution and completion layer&lt;br /&gt;
* [[Introduction to GMMU]] — GPU address translation from first principles&lt;br /&gt;
* [[UVM in the Guest]] — unified memory, semaphores, page trees&lt;br /&gt;
* [[GMMU Multi-Tenant Protection]] — isolation design for multiple VMs and tenants&lt;br /&gt;
* [[Physical GPU Backend and Guest Wiring]] — how guest work reaches real hardware&lt;br /&gt;
* [[Guest Driver Lifecycle: A Field Guide]] — boot to CUDA, with real control IDs and log signatures&lt;br /&gt;
&lt;br /&gt;
== CUDA ==&lt;br /&gt;
* [[CUDA Userspace Driver]] — the &amp;lt;code&amp;gt;libcuda.so&amp;lt;/code&amp;gt; deep dive&lt;br /&gt;
* [[The Execution Frontier]] — the GR compute-launch chain and its current wall&lt;br /&gt;
&lt;br /&gt;
== Firmware and reverse engineering ==&lt;br /&gt;
* [[GSP 570.144W Firmware Analysis]] — how the 28.5 MB image was decompiled and mapped&lt;br /&gt;
* [[Address Reference]] — firmware-side address tables&lt;br /&gt;
* [[risc-v-gsp-rm-debugger]] — the firmware runtime workbench (hooks, watchpoints, sessions)&lt;br /&gt;
* Historical protocol analyses, kept for the record: [[RPC Message Format]] · [[BAR Emulation Specification]] · [[WPR Management]] · [[Migration Protocol]] · [[GSP RPC Emulation]] · [[Error Codes]] · [[vGPU-IO Integration Guide]]&lt;br /&gt;
&lt;br /&gt;
== Portability and ecosystem ==&lt;br /&gt;
* [[Hardware and Software Matrix]] — Reference / Target / Experimental, honestly labelled&lt;br /&gt;
* [[HAAEEP and Collaboration]] — the agent-edge use case, collaboration and licensing models&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
* [[Glossary]]&lt;br /&gt;
* [[FAQ]]&lt;br /&gt;
* [[Error Codes]] — historical naming, superseded by the wire status values&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
This wiki previously hosted the OpenMdev / LibVF.IO project documentation (2021–2023). The pages below are archived for reference; they describe earlier projects and architectures, not Open-IOV.&lt;br /&gt;
&lt;br /&gt;
* [[Introduction]] · [[Virtualization Fundamentals]] · [[Virtual I/O Internals]] · [[GPU Driver Internals]] · [[GPU Firmware]] · [[GPU Support]] · [[CPU Support]] · [[Hypervisor Support]] · [[Merged Drivers]] · [[OpenRM]] · [[AMDGPU]] · [[Intel]] · [[Mdev-GPU]] · [[GVM]] · [[Hyperborea]] · [[LIME Is Mediated Emulation]] · [[LibVF.IO Setup Guide]] · [[Looking Glass KVMFR]] · [[VGPU Unlock]] · [[GPU Software Bill Of Materials (SBOM)]]&lt;br /&gt;
&lt;br /&gt;
== Meta ==&lt;br /&gt;
* [[Open-IOV:About|About Open-IOV]]&lt;br /&gt;
* [[Community]]&lt;br /&gt;
* Wiki architecture pages name their canonical source in the repository; when a page and its source disagree, the repository wins.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Open-IOV:About&amp;diff=23973</id>
		<title>Open-IOV:About</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Open-IOV:About&amp;diff=23973"/>
		<updated>2026-10-12T04:40:24Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links to the cgit tree/repo URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
'''Open-IOV''' is an open-source virtualization layer for NVIDIA GPUs. It runs '''stock, unmodified NVIDIA drivers inside virtual machines''' — Linux and Windows — with GPU compute (CUDA), and eventually 3D graphics and video, on hardware you already own: without a proprietary vGPU license, without patching the guest driver, the host driver, the hypervisor or the GPU firmware.&lt;br /&gt;
&lt;br /&gt;
== Mission ==&lt;br /&gt;
Make NVIDIA GPUs fully virtualizable, by anyone, for any hypervisor, without modifying NVIDIA software, firmware or hardware.&lt;br /&gt;
&lt;br /&gt;
== How it works ==&lt;br /&gt;
The only component the project adds is a host kernel module (&amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt;). It implements the interface the guest driver expects to talk to — the GPU System Processor (GSP) and its resource-manager firmware — and arranges for the guest's work to execute on real GPU hardware. The guiding sentence is:&lt;br /&gt;
&lt;br /&gt;
::'''''Emulate the interface. Pass through the work. Never patch anyone.'''''&lt;br /&gt;
&lt;br /&gt;
See [[System Overview]] for the architecture and [[Project Status]] for the honest current state.&lt;br /&gt;
&lt;br /&gt;
== Principles ==&lt;br /&gt;
* '''No patches anywhere.''' Guest drivers, host drivers, firmware and hypervisors are all used unmodified; interoperability is the goal, not counterfeiting.&lt;br /&gt;
* '''Honest status.''' Claims carry dates and evidence; the project publishes what does not work as clearly as what does.&lt;br /&gt;
* '''Independent IP block.''' Open-IOV is self-contained so KVM, Xen, Argo/OpenXT, Qubes OS Air and others can carry it without forks.&lt;br /&gt;
* '''Durability by owning the interface.''' The protocol, not a snapshot of it, is reimplemented — so new driver versions, firmware and hardware can be carried forward.&lt;br /&gt;
&lt;br /&gt;
== Licensing ==&lt;br /&gt;
'''All documentation on this site is licensed [https://creativecommons.org/licenses/by/4.0/ CC-BY-4.0]''' — the statement carried at the top of every page. It may be reused with attribution, or used as inspiration for new documentation, including by GPU vendors for public commercial distribution as developer documentation.&lt;br /&gt;
&lt;br /&gt;
The project's source code is licensed separately: '''BSD 3-Clause''' for everything reusable (userspace libraries, tools, scripts, configuration) and '''GPL-2.0''' for the kernel modules that must legally link against GPL-only kernel exports (VFIO, mdev, IOMMU); per-file SPDX identifiers govern. NVIDIA's software and firmware are used unmodified and are not redistributed. See the repository's &amp;lt;code&amp;gt;LICENSE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;docs/09-reference/legal-and-licensing.md&amp;lt;/code&amp;gt; for the full statement.&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
* Source and issues: [https://git.vgpu.io/open-iov.git/ git.vgpu.io/open-iov]&lt;br /&gt;
* Chat: [https://discord.gg/Rb9K9DYxKK Open-IOV Discord]&lt;br /&gt;
* See [[Community]] and [[HAAEEP and Collaboration]].&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Main_Page&amp;diff=23972</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Main_Page&amp;diff=23972"/>
		<updated>2026-10-12T04:40:23Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links to the cgit tree/repo URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&amp;lt;div style=&amp;quot;border:1px solid #c8ccd1; background:#f8f9fa; padding:0.9em 1.2em; margin-bottom:1em;&amp;quot;&amp;gt;&lt;br /&gt;
'''Open-IOV''' is an open-source virtualization layer for NVIDIA GPUs: it runs '''stock, unmodified NVIDIA drivers inside virtual machines''' — Linux and Windows — with CUDA on hardware you own, '''without proprietary vGPU licenses''', without patching the guest driver, the host driver, the hypervisor or the firmware.&lt;br /&gt;
&lt;br /&gt;
'''''Emulate the interface. Pass through the work. Never patch anyone.'''''&lt;br /&gt;
&lt;br /&gt;
The only new component is one host kernel module (&amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt;), which implements the interface the guest driver expects to talk to — the GPU System Processor and its resource-manager firmware — and arranges for the guest's work to run on real GPU hardware.&lt;br /&gt;
&lt;br /&gt;
'''[[Open-IOV:About|About Open-IOV]]''' · '''[[Community|Community]]''' · '''[[Documentation|Documentation]]'''&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Start here ==&lt;br /&gt;
* '''[[Project Status]]''' — the honest, dated state of the project.&lt;br /&gt;
* '''[[Install and First Run]]''' — fresh host to a stock guest driver in about half an hour.&lt;br /&gt;
* '''[[System Overview]]''' — how Open-IOV works, in one page.&lt;br /&gt;
* '''[[Documentation]]''' — the full index of this wiki.&lt;br /&gt;
* '''[[FAQ]]''' — the questions we get asked most.&lt;br /&gt;
&lt;br /&gt;
== Project status (2026-10-12) ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Area !! State&lt;br /&gt;
|-&lt;br /&gt;
| Emulated vGPU device (PCI, BARs, MSI-X, VFIO mdev) || Working&lt;br /&gt;
|-&lt;br /&gt;
| GSP boot emulation and GSP-RM message queues / RPC || Working&lt;br /&gt;
|-&lt;br /&gt;
| Stock guest driver probe, nvidia-smi (TU104) || Working&lt;br /&gt;
|-&lt;br /&gt;
| CUDA userspace init and the driver-API smoke (ALL OK, 64-byte payload round-trips) || Working&lt;br /&gt;
|-&lt;br /&gt;
| Guest CUDA kernel execution on real hardware || In progress — a forwarded launch reaches the engine queue; engine execution is the frontier&lt;br /&gt;
|-&lt;br /&gt;
| OpenGL / Vulkan, Windows guests, multi-tenancy, migration, performance || Not yet&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The full story, with evidence and the current wall: [[Project Status]] and [[The Execution Frontier]].&lt;br /&gt;
&lt;br /&gt;
== Deep dives ==&lt;br /&gt;
* [[System Overview]] — the architecture before any subsystem&lt;br /&gt;
* [[GSP and GSP-RM]] — the firmware interface we emulate&lt;br /&gt;
* [[The vGSP Execution Plane (vEP)]] — how guest work becomes execution and completion&lt;br /&gt;
* [[The Host Module (vgsp.ko)]] — the module internals&lt;br /&gt;
* [[The Guest Stack and CUDASW]] — what runs unmodified in the guest&lt;br /&gt;
* [[CUDA Userspace Driver]] — the &amp;lt;code&amp;gt;libcuda.so&amp;lt;/code&amp;gt; analysis&lt;br /&gt;
* [[Introduction to GMMU]] — GPU address translation from first principles&lt;br /&gt;
* [[UVM in the Guest]] — unified memory as a correctness oracle&lt;br /&gt;
* [[Physical GPU Backend and Guest Wiring]] — how work reaches real hardware&lt;br /&gt;
* [[The Execution Frontier]] — the leading edge, evidence-led&lt;br /&gt;
* [[Guest Driver Lifecycle: A Field Guide]] — boot to CUDA with real IDs and log signatures&lt;br /&gt;
&lt;br /&gt;
== Firmware interoperability ==&lt;br /&gt;
* [[GSP 570.144W Firmware Analysis]]&lt;br /&gt;
* [[Address Reference]]&lt;br /&gt;
* [[RPC Message Format]] · [[BAR Emulation Specification]] · [[WPR Management]] · [[Migration Protocol]] · [[GSP RPC Emulation]] (historical, superseded)&lt;br /&gt;
* [[risc-v-gsp-rm-debugger]] — the firmware runtime workbench&lt;br /&gt;
&lt;br /&gt;
== Project and ecosystem ==&lt;br /&gt;
* [[Hardware and Software Matrix]] — supported combinations, honestly labelled&lt;br /&gt;
* [[HAAEEP and Collaboration]] — the agent-edge use case and how to work with us&lt;br /&gt;
* [[FAQ]] · [[Glossary]]&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
* Source and issues: [https://git.vgpu.io/open-iov.git/ git.vgpu.io/open-iov]&lt;br /&gt;
* Chat: [https://discord.gg/Rb9K9DYxKK Open-IOV Discord]&lt;br /&gt;
&lt;br /&gt;
== About Open-IOV ==&lt;br /&gt;
Open-IOV runs unmodified NVIDIA driver stacks inside virtual machines with GPU compute on hardware you own — no proprietary vGPU license, and no patches to the guest driver, the host driver, the hypervisor or the firmware. The project adds one host kernel module (&amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt;) that implements the interface the guest driver expects to talk to — the GPU System Processor and its resource-manager firmware — and arranges for the guest's work to run on real GPU hardware.&lt;br /&gt;
&lt;br /&gt;
* '''Mission:''' make NVIDIA GPUs fully virtualizable, by anyone, for any hypervisor, without modifying NVIDIA software, firmware or hardware.&lt;br /&gt;
* '''Principles:''' no patches anywhere; honest status carried with dated evidence; an independent, self-contained IP block; durability by owning the interface rather than a snapshot of it.&lt;br /&gt;
* '''Licensing:''' all documentation on this site is [https://creativecommons.org/licenses/by/4.0/ CC-BY-4.0]; the project's code is BSD-3-Clause (GPL-2.0 for the kernel modules); NVIDIA software and firmware are used unmodified and are not redistributed.&lt;br /&gt;
&lt;br /&gt;
'''[[Open-IOV:About|Read more about Open-IOV →]]'''&lt;br /&gt;
&lt;br /&gt;
== About this wiki ==&lt;br /&gt;
This wiki previously hosted documentation from the earlier project era (2021–2023). Those pages are retained for reference under [[Documentation|History]]; current documentation starts at [[Documentation]].&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=GSP_RPC_Emulation&amp;diff=23971</id>
		<title>GSP RPC Emulation</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=GSP_RPC_Emulation&amp;diff=23971"/>
		<updated>2026-10-12T04:40:10Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= GSP vGPU RPC Emulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' This page describes an earlier emulation-mode design and is retained for reference only. The project does '''not''' use NVIDIA's proprietary vGPU stack. Canonical documentation: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/03-gsp-and-gsp-rm.md &amp;lt;code&amp;gt;../docs/03-architecture/03-gsp-and-gsp-rm.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Open-IOV includes '''emulation mode''' that allows operation with unmodified consumer/OpenRM GSP firmware by emulating missing vGPU RPC handlers locally in kernel and userspace.&lt;br /&gt;
&lt;br /&gt;
== Problem ==&lt;br /&gt;
&lt;br /&gt;
The NVIDIA GSP firmware on consumer drivers (550.163.01) and OpenRM lacks the vGPU-specific RPC handlers that exist only in the GRID host driver firmware:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Handler&lt;br /&gt;
! Address&lt;br /&gt;
! Size&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| BAR Trap&lt;br /&gt;
| 0x04CB8188&lt;br /&gt;
| 40KB&lt;br /&gt;
| BAR1/ForceBarAccess/Aperture&lt;br /&gt;
|-&lt;br /&gt;
| WPR Handler 1&lt;br /&gt;
| 0x04F00B0C&lt;br /&gt;
| 62KB&lt;br /&gt;
| Write/Read Protect Regions&lt;br /&gt;
|-&lt;br /&gt;
| WPR Handler 2&lt;br /&gt;
| 0x04F00C78&lt;br /&gt;
| 62KB&lt;br /&gt;
| Write/Read Protect Regions&lt;br /&gt;
|-&lt;br /&gt;
| Migration&lt;br /&gt;
| 0x04179ED8/0x04179FBC&lt;br /&gt;
| -&lt;br /&gt;
| Live migration&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Without these handlers, VF creation times out at BAR configuration (RPC to 0x04CB8188).&lt;br /&gt;
&lt;br /&gt;
== Solution: Emulation Mode ==&lt;br /&gt;
&lt;br /&gt;
Emulation mode intercepts vGPU RPC calls and handles them locally instead of sending to GSP:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;┌─────────────────────────────────────────────────────────────────┐&lt;br /&gt;
│                    Emulation Architecture                        │&lt;br /&gt;
├─────────────────────────────────────────────────────────────────┤&lt;br /&gt;
│                                                                  │&lt;br /&gt;
│  Userspace App (libiov.so)                                       │&lt;br /&gt;
│       │                                                          │&lt;br /&gt;
│       ▼                                                          │&lt;br /&gt;
│  ┌─────────────────┐     ┌─────────────────┐                   │&lt;br /&gt;
│  │ Kernel IOCTL    │────▶│ Emulation Layer │                   │&lt;br /&gt;
│  │ Handler         │     │ (kernel)        │                   │&lt;br /&gt;
│  └─────────────────┘     └────────┬────────┘                   │&lt;br /&gt;
│                                    │                            │&lt;br /&gt;
│                    ┌───────────────┼───────────────┐           │&lt;br /&gt;
│                    ▼               ▼               ▼           │&lt;br /&gt;
│             ┌──────────┐    ┌──────────┐    ┌──────────┐      │&lt;br /&gt;
│             │ BAR Emu  │    │ WPR Emu  │    │ Mem Emu  │      │&lt;br /&gt;
│             │ (kernel) │    │ (kernel) │    │ (kernel) │      │&lt;br /&gt;
│             └──────────┘    └──────────┘    └──────────┘      │&lt;br /&gt;
│                    │               │               │           │&lt;br /&gt;
│                    ▼               ▼               ▼           │&lt;br /&gt;
│             ┌──────────────────────────────────────────┐       │&lt;br /&gt;
│             │         Userspace Emulator (libiov.so)   │       │&lt;br /&gt;
│             │  rpc_emu_bar_*(), rpc_emu_wpr_*()        │       │&lt;br /&gt;
│             └──────────────────────────────────────────┘       │&lt;br /&gt;
│                                                                  │&lt;br /&gt;
└─────────────────────────────────────────────────────────────────┘&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Auto-Detection (Default Behavior) ==&lt;br /&gt;
&lt;br /&gt;
'''Emulation mode is ON by default''' and auto-detects at driver load:&lt;br /&gt;
&lt;br /&gt;
# Driver initializes RPC communication with GSP&lt;br /&gt;
# Sends test &amp;lt;code&amp;gt;BAR_TRAP&amp;lt;/code&amp;gt; RPC (non-destructive READ)&lt;br /&gt;
# '''If GSP responds''' (ret=0) → vGPU handlers present → '''emulation disabled'''&lt;br /&gt;
# '''If GSP times out/errors''' (ret=-ETIMEDOUT/-EIO/-ENODEV) → handlers missing → '''emulation enabled'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dmesg output:&lt;br /&gt;
  gsp-vgpu: Auto-detecting GSP vGPU RPC handler support...&lt;br /&gt;
  gsp-vgpu: GSP lacks vGPU RPC handlers (ret=-110) - ENABLING emulation mode&lt;br /&gt;
  # or&lt;br /&gt;
  gsp-vgpu: GSP has vGPU RPC handlers - DISABLING emulation mode&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module Parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;emulation_mode&amp;lt;/code&amp;gt;&lt;br /&gt;
| bool&lt;br /&gt;
| 1 (ON)&lt;br /&gt;
| Current state (read-only, shows auto-detected value)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;emulation_override&amp;lt;/code&amp;gt;&lt;br /&gt;
| bool&lt;br /&gt;
| 0 (auto)&lt;br /&gt;
| Override: 1=force emulation ON, 0=force emulation OFF&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# Default: auto-detect&lt;br /&gt;
sudo insmod gsp-vgpu.ko firmware_name=gsp-570.144.fwimage.bin&lt;br /&gt;
&lt;br /&gt;
# Force emulation ON (testing with GRID GSP)&lt;br /&gt;
sudo insmod gsp-vgpu.ko firmware_name=gsp-570.144.fwimage.bin emulation_override=1&lt;br /&gt;
&lt;br /&gt;
# Force emulation OFF (requires GRID GSP)&lt;br /&gt;
sudo insmod gsp-vgpu.ko firmware_name=gsp-570.144.fwimage.bin emulation_override=0&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Emulated RPC Handlers ==&lt;br /&gt;
&lt;br /&gt;
=== Kernel Emulation (&amp;lt;code&amp;gt;driver/&amp;lt;/code&amp;gt;) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! RPC Type&lt;br /&gt;
! Handler&lt;br /&gt;
! Emulation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GSP_RPC_ALLOC&amp;lt;/code&amp;gt; (0x01)&lt;br /&gt;
| &amp;lt;code&amp;gt;gsp_vf_mem_alloc()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Synthetic handles/VAs from local counter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GSP_RPC_PIN&amp;lt;/code&amp;gt; (0x05)&lt;br /&gt;
| &amp;lt;code&amp;gt;gsp_vf_mem_pin()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Synthetic DMA addresses from local counter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GSP_RPC_MAP&amp;lt;/code&amp;gt; (0x03)&lt;br /&gt;
| &amp;lt;code&amp;gt;gsp_vf_mem_map()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Identity map (return requested VA)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GSP_RPC_BAR_TRAP&amp;lt;/code&amp;gt; (0x0A)&lt;br /&gt;
| &amp;lt;code&amp;gt;gsp_bar_trap_handler()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Local aperture/force_access state&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GSP_RPC_MAP&amp;lt;/code&amp;gt; (WPR)&lt;br /&gt;
| &amp;lt;code&amp;gt;gsp_vf_wpr_protect()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Local WPR region list&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;GSP_RPC_UNMAP&amp;lt;/code&amp;gt; (WPR)&lt;br /&gt;
| &amp;lt;code&amp;gt;gsp_vf_wpr_unprotect()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Local WPR region removal&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Userspace Emulation (&amp;lt;code&amp;gt;userspace/lib/rpc_emulator.c&amp;lt;/code&amp;gt;) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Function&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_emu_bar_config()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Local aperture offset/size + backing store&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_emu_bar_force_access()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Local force_access state&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_emu_bar_save/restore()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Migration state serialization&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_emu_wpr_protect_write/read()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Local WPR region tracking&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_emu_wpr_unprotect()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Local WPR region removal&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_emu_wpr_set_timeout()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Local timeout tracking&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_emu_wpr_check_access()&amp;lt;/code&amp;gt;&lt;br /&gt;
| Access violation detection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Emulation Data Structures ==&lt;br /&gt;
&lt;br /&gt;
=== BAR State (per VF) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct gsp_bar_state {&lt;br /&gt;
    uint64_t aperture_offset;   // BAR1 aperture base&lt;br /&gt;
    uint64_t aperture_size;     // BAR1 aperture size (max 256KB)&lt;br /&gt;
    bool force_access;          // ForceBarAccess enabled&lt;br /&gt;
    uint32_t force_vf;          // VF holding force access&lt;br /&gt;
    void *backing_store;        // Emulated BAR memory&lt;br /&gt;
    size_t backing_size;        // Backing store size&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WPR Region List (per VF) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct gsp_wpr_region {&lt;br /&gt;
    struct list_head list;&lt;br /&gt;
    uint64_t base;              // Region base address&lt;br /&gt;
    uint64_t size;              // Region size&lt;br /&gt;
    uint32_t flags;             // GSP_WPR_WRITE/READ/EXECUTE&lt;br /&gt;
    uint32_t vf_id;             // Owning VF&lt;br /&gt;
    void (*completion_cb)(...); // Write/read complete callback&lt;br /&gt;
    void (*timeout_cb)(...);    // Timeout callback&lt;br /&gt;
    uint64_t timeout_ns;        // Timeout in nanoseconds&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Userspace Emulator State ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct emu_bar_state {&lt;br /&gt;
    uint64_t aperture_offset;&lt;br /&gt;
    uint64_t aperture_size;&lt;br /&gt;
    bool force_access;&lt;br /&gt;
    uint32_t force_vf;&lt;br /&gt;
    void *backing_store;&lt;br /&gt;
    size_t backing_size;&lt;br /&gt;
    pthread_mutex_t lock;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
struct emu_wpr_state {&lt;br /&gt;
    struct emu_wpr_region *regions;  // Linked list&lt;br /&gt;
    pthread_mutex_t lock;&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Fallback Logic ==&lt;br /&gt;
&lt;br /&gt;
Userspace library (&amp;lt;code&amp;gt;libiov.so&amp;lt;/code&amp;gt;) implements fallback:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;vgpu_error_t vgpu_bar_config(vgpu_vf_t vf, uint64_t offset, uint64_t size) {&lt;br /&gt;
    // 1. Try kernel IOCTL (sends RPC to GSP)&lt;br /&gt;
    ret = ioctl(fd, GSP_IOCTL_BAR_CONFIG, &amp;amp;amp;args);&lt;br /&gt;
    &lt;br /&gt;
    // 2. If GSP lacks handlers (ENOTSUP/ETIMEDOUT/EIO), use emulator&lt;br /&gt;
    if (ret &amp;amp;lt; 0 &amp;amp;amp;&amp;amp;amp; dev-&amp;amp;gt;emulation_enabled &amp;amp;amp;&amp;amp;amp; &lt;br /&gt;
        (errno == ENOTSUP || errno == ETIMEDOUT || errno == EIO)) {&lt;br /&gt;
        return rpc_emu_bar_config(vf-&amp;amp;gt;id, offset, size);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return map_errno(errno);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Feature&lt;br /&gt;
! Emulation Status&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| BAR Aperture Config&lt;br /&gt;
| ✅ Full&lt;br /&gt;
| Local state + backing store&lt;br /&gt;
|-&lt;br /&gt;
| ForceBarAccess&lt;br /&gt;
| ✅ Full&lt;br /&gt;
| Per-VF exclusive access&lt;br /&gt;
|-&lt;br /&gt;
| BAR Save/Restore&lt;br /&gt;
| ✅ Full&lt;br /&gt;
| Migration support&lt;br /&gt;
|-&lt;br /&gt;
| WPR Write Protect&lt;br /&gt;
| ✅ Full&lt;br /&gt;
| Region tracking + access check&lt;br /&gt;
|-&lt;br /&gt;
| WPR Read Protect&lt;br /&gt;
| ✅ Full&lt;br /&gt;
| Region tracking + access check&lt;br /&gt;
|-&lt;br /&gt;
| WPR Timeout&lt;br /&gt;
| ✅ Partial&lt;br /&gt;
| Timeout stored, callbacks not wired&lt;br /&gt;
|-&lt;br /&gt;
| Memory Alloc&lt;br /&gt;
| ✅ Basic&lt;br /&gt;
| Synthetic handles/VAs&lt;br /&gt;
|-&lt;br /&gt;
| Memory Pin&lt;br /&gt;
| ✅ Basic&lt;br /&gt;
| Synthetic DMA addresses&lt;br /&gt;
|-&lt;br /&gt;
| Memory Map&lt;br /&gt;
| ✅ Basic&lt;br /&gt;
| Identity mapping&lt;br /&gt;
|-&lt;br /&gt;
| Migration&lt;br /&gt;
| ⚠️ Partial&lt;br /&gt;
| BAR/WPR state only&lt;br /&gt;
|-&lt;br /&gt;
| Scheduling&lt;br /&gt;
| ❌ No&lt;br /&gt;
| Returns success, no actual scheduling&lt;br /&gt;
|-&lt;br /&gt;
| Notifications&lt;br /&gt;
| ❌ No&lt;br /&gt;
| No async event delivery&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Testing Emulation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# 1. Load driver (auto-enables emulation on consumer GSP)&lt;br /&gt;
sudo insmod driver/gsp-vgpu.ko firmware_name=gsp-570.144.fwimage.bin&lt;br /&gt;
&lt;br /&gt;
# 2. Verify emulation enabled in dmesg&lt;br /&gt;
dmesg -T | grep -i emulation&lt;br /&gt;
# gsp-vgpu: GSP lacks vGPU RPC handlers (ret=-110) - ENABLING emulation mode&lt;br /&gt;
&lt;br /&gt;
# 3. Run example - should complete without timeouts&lt;br /&gt;
sudo LD_LIBRARY_PATH=userspace/lib ./userspace/examples/example_vgpu /dev/gsp-vgpu&lt;br /&gt;
&lt;br /&gt;
# 4. Check debugfs for emulated state&lt;br /&gt;
cat /sys/kernel/debug/gsp-vgpu/vfs/vf1/bar_state&lt;br /&gt;
cat /sys/kernel/debug/gsp-vgpu/vfs/vf1/wpr_regions&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Future Work ==&lt;br /&gt;
&lt;br /&gt;
* [ ] Wire WPR timeout callbacks to kernel timers&lt;br /&gt;
* [ ] Implement emulated scheduling with work queues&lt;br /&gt;
* [ ] Add async notification support via eventfd&lt;br /&gt;
* [ ] Complete migration state for WPR regions&lt;br /&gt;
* [ ] Performance optimization (batch RPC emulation)&lt;br /&gt;
* [ ] Conformance tests vs GRID GSP behavior&lt;br /&gt;
&lt;br /&gt;
== Related Documentation ==&lt;br /&gt;
&lt;br /&gt;
* [[BAR Emulation Specification]]&lt;br /&gt;
* [[WPR Management]]&lt;br /&gt;
* [[RPC Message Format]]&lt;br /&gt;
* [[VGPU-IO Integration Guide|Integration Guide]]&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=GSP_570.144W_Firmware_Analysis&amp;diff=23970</id>
		<title>GSP 570.144W Firmware Analysis</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=GSP_570.144W_Firmware_Analysis&amp;diff=23970"/>
		<updated>2026-10-12T04:40:09Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= NVIDIA GSP 570.144W Firmware Analysis (TU102/TU104) =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Retained firmware-analysis record.''' This page documents the GSP 570.144W firmware binary (decompilation and firmware-side addresses) and the address tables below are the firmware-side record, not the host implementation. Current host architecture: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/03-gsp-and-gsp-rm.md &amp;lt;code&amp;gt;../docs/03-architecture/03-gsp-and-gsp-rm.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;]. The decompiled analysis output is not distributed; the file names below are&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the analysis record.&lt;br /&gt;
&lt;br /&gt;
== Binary Information ==&lt;br /&gt;
&lt;br /&gt;
* '''File''': &amp;lt;code&amp;gt;gsp-570.144.fwimage.bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* '''Size''': 28.5 MB&lt;br /&gt;
* '''Format''': ELF, RV64IMAC (RISC-V 64-bit)&lt;br /&gt;
* '''Base Address''': 0x04000000&lt;br /&gt;
* '''MD5''': &amp;lt;code&amp;gt;13ce12a392a31eeb79a2e6ebd3a4a93a&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Map ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;0x04000000 - 0x05FFFFFF  : Code + Read-only data (~32 MB)&lt;br /&gt;
0x04296040               : Global state structure (cRam0000000004296048)&lt;br /&gt;
0x0429B750               : Error/status registers&lt;br /&gt;
0x041DC350               : Stack canary / frame guard&lt;br /&gt;
0x429B000 - 0x429BFFF    : Memory allocator arena (0x429B450 = alloc entry)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Calling Convention (RISC-V RV64IMAC) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Register&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| s0 (x8)&lt;br /&gt;
| Frame pointer&lt;br /&gt;
|-&lt;br /&gt;
| s1 (x9), s4 (x12), s10 (x20)&lt;br /&gt;
| RA save locations&lt;br /&gt;
|-&lt;br /&gt;
| s1-s11&lt;br /&gt;
| Callee-saved (pushed to stack)&lt;br /&gt;
|-&lt;br /&gt;
| a0-a7&lt;br /&gt;
| Arguments / return values&lt;br /&gt;
|-&lt;br /&gt;
| sp&lt;br /&gt;
| Stack pointer (grows down, frames 96-560 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== RPC System ==&lt;br /&gt;
&lt;br /&gt;
=== 12 RPC Types (Jump Table at 0x059BFEB0) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Type&lt;br /&gt;
! Name&lt;br /&gt;
! Handler A&lt;br /&gt;
! Handler B&lt;br /&gt;
! Dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x01&lt;br /&gt;
| ALLOC&lt;br /&gt;
| —&lt;br /&gt;
| —&lt;br /&gt;
| Primary&lt;br /&gt;
|-&lt;br /&gt;
| 0x02&lt;br /&gt;
| FREE&lt;br /&gt;
| —&lt;br /&gt;
| —&lt;br /&gt;
| Primary&lt;br /&gt;
|-&lt;br /&gt;
| 0x03&lt;br /&gt;
| MAP&lt;br /&gt;
| 0x05766AB7&lt;br /&gt;
| 0x05778A37&lt;br /&gt;
| Secondary&lt;br /&gt;
|-&lt;br /&gt;
| 0x04&lt;br /&gt;
| UNMAP&lt;br /&gt;
| 0x057669B7&lt;br /&gt;
| 0x05779937&lt;br /&gt;
| Primary + Secondary&lt;br /&gt;
|-&lt;br /&gt;
| 0x05&lt;br /&gt;
| PIN&lt;br /&gt;
| 0x057664B7&lt;br /&gt;
| 0x0577A3B7&lt;br /&gt;
| Secondary&lt;br /&gt;
|-&lt;br /&gt;
| 0x06&lt;br /&gt;
| UNPIN&lt;br /&gt;
| 0x057682B7&lt;br /&gt;
| 0x05779FB7&lt;br /&gt;
| Secondary&lt;br /&gt;
|-&lt;br /&gt;
| 0x07&lt;br /&gt;
| SCHEDULE&lt;br /&gt;
| 0x05767F37&lt;br /&gt;
| 0x0575AEB7&lt;br /&gt;
| Primary + Secondary&lt;br /&gt;
|-&lt;br /&gt;
| 0x08&lt;br /&gt;
| YIELD&lt;br /&gt;
| 0x0575AE37&lt;br /&gt;
| 0x05767337&lt;br /&gt;
| Secondary&lt;br /&gt;
|-&lt;br /&gt;
| 0x09&lt;br /&gt;
| NOTIFY&lt;br /&gt;
| 0x0577C8B7&lt;br /&gt;
| 0x05767837&lt;br /&gt;
| Secondary&lt;br /&gt;
|-&lt;br /&gt;
| 0x0A&lt;br /&gt;
| BAR_TRAP&lt;br /&gt;
| 0x057675B7&lt;br /&gt;
| —&lt;br /&gt;
| Secondary&lt;br /&gt;
|-&lt;br /&gt;
| 0x0B&lt;br /&gt;
| MIGRATE&lt;br /&gt;
| —&lt;br /&gt;
| —&lt;br /&gt;
| Primary&lt;br /&gt;
|-&lt;br /&gt;
| 0x0C&lt;br /&gt;
| DEBUG&lt;br /&gt;
| —&lt;br /&gt;
| —&lt;br /&gt;
| —&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Primary Dispatcher (0x057A1AC0) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Entry: FUN_ram_057a1ac0(param_1, param_2, param_3, param_4, *out_id, *out_a, *out_b, *out_c)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Extracts RPC type from &amp;lt;code&amp;gt;param_1&amp;lt;/code&amp;gt;&lt;br /&gt;
* Validates against max type (bgeu x12, x13 checks for types 11 and 13)&lt;br /&gt;
* MIGRATE (0x0B) branches at 0x057A1BDC and 0x057A1D54&lt;br /&gt;
* Indexes into 32-entry jump table at '''0x057A3AD8'''&lt;br /&gt;
&lt;br /&gt;
==== Primary Dispatcher Sub-Command Jump Table (0x057A3AD8) ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Subcmd&lt;br /&gt;
! Target&lt;br /&gt;
! Decompiled&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x057A1DB4&lt;br /&gt;
| ✅&lt;br /&gt;
| Returns ID=0x40&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| 0x057A1C18&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| 0x057A39FC&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 0x057A1BCC&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 0x057A1EF4&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 0x057A1E94&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 0x057A3A28&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| 0x057A3A60&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| 0x057A1C6C&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| 0x057A3A48&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| 0x057A1F6C&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| 0x057A3AC4&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| 0x057A1E10&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| 0x057A3A90&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| 0x057A39BC&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| 0x057A3AAC&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| 0x057A3A78&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| 0x057A1CCC&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| 0x057A39E0&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| 0x057A1FA8&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| 0x057A2094&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| 0x057A2074&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| 0x057A2044&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| 0x057A20D4&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| 0x057A20B4&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| 0x057A1FC8&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 26&lt;br /&gt;
| 0x057A2008&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 27&lt;br /&gt;
| 0x057A1FE8&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 28&lt;br /&gt;
| 0x057A2024&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 29&lt;br /&gt;
| 0x057A219C&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 30&lt;br /&gt;
| 0x057A20FC&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 31&lt;br /&gt;
| 0x057A214C&lt;br /&gt;
| ✅&lt;br /&gt;
| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Pattern''': Each sub-command returns a constant ID in &amp;lt;code&amp;gt;*out_id&amp;lt;/code&amp;gt; (e.g., 0x10, 0x14, 0x40) and echoes input params to output pointers.&lt;br /&gt;
&lt;br /&gt;
=== Secondary Dispatcher (0x04ED39DC) ===&lt;br /&gt;
&lt;br /&gt;
* Branch-based dispatch for ALL 11 RPC types&lt;br /&gt;
* 141 KB decompiled — handles MAP, UNMAP, PIN, UNPIN, SCHEDULE, YIELD, NOTIFY, BAR_TRAP&lt;br /&gt;
* Entry: 0x04ED34B8 (PIN handler from secondary)&lt;br /&gt;
&lt;br /&gt;
=== Specialized Main Handlers ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Function&lt;br /&gt;
! Address&lt;br /&gt;
! Size&lt;br /&gt;
! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_alloc_main&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x057E94EC&lt;br /&gt;
| 40 KB&lt;br /&gt;
| Core ALLOC implementation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_schedule_main&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x051EFBF4&lt;br /&gt;
| 1.8 KB&lt;br /&gt;
| Core SCHEDULE implementation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_bar_trap_handler&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x04CB8188&lt;br /&gt;
| 40 KB&lt;br /&gt;
| BAR1 emulation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_pin_handler&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x04ED34B8&lt;br /&gt;
| —&lt;br /&gt;
| PIN from secondary dispatcher&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== BAR Emulation (RPC 0x0A) ==&lt;br /&gt;
&lt;br /&gt;
=== Handler: 0x04CB8188 (40 KB) ===&lt;br /&gt;
&lt;br /&gt;
'''Strings Referenced''':&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;BAR1&amp;lt;/code&amp;gt; at 0x0406570E, 0x04085DE0&lt;br /&gt;
* &amp;lt;code&amp;gt;Bar1Rest&amp;lt;/code&amp;gt; at 0x040656DA&lt;br /&gt;
* &amp;lt;code&amp;gt;ForceBarAccess&amp;lt;/code&amp;gt; at 0x040656F2&lt;br /&gt;
* &amp;lt;code&amp;gt;Bar1Aperture&amp;lt;/code&amp;gt; at 0x04065722&lt;br /&gt;
&lt;br /&gt;
'''Key Operations''':&lt;br /&gt;
&lt;br /&gt;
* Memory allocation via &amp;lt;code&amp;gt;UNK_ram_058A1A9C&amp;lt;/code&amp;gt; at arena 0x429B450&lt;br /&gt;
* Buffer management with 0x429B428 (cache/flush)&lt;br /&gt;
* Error codes: 0x51 (OOM), 0x1E (timeout), 0x1D, 0x1F, 0x25, 0x37, 0x56&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;ebreak&amp;lt;/code&amp;gt; for fatal errors with logging at 0x05AB7DA0&lt;br /&gt;
* Stack canary check against 0x041DC350&lt;br /&gt;
&lt;br /&gt;
'''Integration Point for vGPU-IO''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Register BAR trap handler at 0x04CB8188&lt;br /&gt;
// Monitor BAR1, Bar1Rest, ForceBarAccess, Bar1Aperture registers&lt;br /&gt;
// Emulate BAR1 aperture/size for guest VF&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== WPR Management ==&lt;br /&gt;
&lt;br /&gt;
=== Handlers: 0x04F00B0C, 0x04F00C78 (62 KB each) ===&lt;br /&gt;
&lt;br /&gt;
'''String References (60 locations)''':&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;WPR_WRITE_COMPLETE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WPR_READ_COMPLETE&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;WPR_WRITE_TIMEOUT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WPR_READ_TIMEOUT&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;NV_WPR_WRITE_COMPLETE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;NV_WPR_READ_COMPLETE&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;NV_WPR_WRITE_TIMEOUT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;NV_WPR_READ_TIMEOUT&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Key Operations''':&lt;br /&gt;
&lt;br /&gt;
* VBIOS parsing (checks for &amp;lt;code&amp;gt;0xAA55&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x57464F4E&amp;lt;/code&amp;gt; &amp;quot;WFON&amp;quot;, &amp;lt;code&amp;gt;0x5746564E&amp;lt;/code&amp;gt; &amp;quot;WFVN&amp;quot;)&lt;br /&gt;
* Memory allocation at 0x429B450&lt;br /&gt;
* DMA/copy via &amp;lt;code&amp;gt;UNK_ram_0588F9C4&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;UNK_ram_05AEC86C&amp;lt;/code&amp;gt;&lt;br /&gt;
* State machine with completion/timeout handling&lt;br /&gt;
* Error codes: 0x1E-0x25, 0x37, 0x51, 0x56, 0xFFFF&lt;br /&gt;
&lt;br /&gt;
'''Integration Point for vGPU-IO''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Hook WPR completion callbacks from string reference locations&lt;br /&gt;
// Implement NV_WPR_WRITE/READ_COMPLETE/TIMEOUT notifications&lt;br /&gt;
// Manage WPR regions for guest VF memory isolation&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Migration Protocol (RPC 0x0B) ==&lt;br /&gt;
&lt;br /&gt;
=== Dual Jump Tables ===&lt;br /&gt;
&lt;br /&gt;
==== Table 1: 0x04179ED8 (Primary dispatcher MIGRATE branch at 0x057A1BDC) ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Index&lt;br /&gt;
! Target&lt;br /&gt;
! Decompiled&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x057A2344&lt;br /&gt;
| ✅ Returns ID=0x14, reads flag at &amp;lt;code&amp;gt;in_t1+0x7F9&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| 0x057A2320&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| 0x057A230C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 0x057A22F8&lt;br /&gt;
| ✅ Returns ID=0x10&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 0x057A2388&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 0x057A23D8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 0x057A23AC&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| 0x057A2478&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| 0x057A2428&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| 0x057A2454&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| 0x057A2404&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| 0x057A2364&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| 0x057A299C&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Table 2: 0x04179FBC (Primary dispatcher MIGRATE branch at 0x057A1D5C) ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Index&lt;br /&gt;
! Target&lt;br /&gt;
! Decompiled&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x057A257C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| 0x057A25E4&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| 0x057A24EC&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 0x057A2608&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 0x057A2534&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 0x057A25C0&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 0x057A24A4&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| 0x057A259C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| 0x057A2510&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| 0x057A2558&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| 0x057A24C8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| 0x057A262C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| 0x057A345C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| 0x057A36D8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| 0x057A35D8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| 0x057A3658&lt;br /&gt;
| ✅&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Pattern''': Migration sub-commands follow same descriptor pattern as primary dispatcher — return constant ID, echo params.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Entry Point &amp;amp;amp; Boot Sequence ==&lt;br /&gt;
&lt;br /&gt;
=== 0x04009000 (573 bytes) ===&lt;br /&gt;
&lt;br /&gt;
* Initializes global state at 0x04296040&lt;br /&gt;
* Sets up stack canary at 0x041DC350&lt;br /&gt;
* Configures memory allocator arena at 0x429B450&lt;br /&gt;
* Registers RPC dispatchers&lt;br /&gt;
* Jumps to main scheduler loop&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Decompiled Output Directory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;decompiled/  (analysis output, not distributed)&lt;br /&gt;
├── entry_ram_04009000.c                    # Boot entry&lt;br /&gt;
├── FUN_ram_04cb8188_ram_04cb8188.c         # BAR trap handler (40 KB)&lt;br /&gt;
├── FUN_ram_04cc58f8_ram_04cc58f8.c         # Secondary dispatcher (141 KB)&lt;br /&gt;
├── FUN_ram_04d00a18_ram_04d00a18.c         # ALLOC-dominant (142 KB)&lt;br /&gt;
├── FUN_ram_04ed39dc_ram_04ed39dc.c         # Secondary dispatcher (141 KB)&lt;br /&gt;
├── FUN_ram_04f00b0c_ram_04f00b0c.c         # WPR handler 1 (62 KB)&lt;br /&gt;
├── FUN_ram_04f00c78_ram_04f00c78.c         # WPR handler 2 (62 KB)&lt;br /&gt;
├── FUN_ram_051efbf4_ram_051efbf4.c         # SCHEDULE main (1.8 KB)&lt;br /&gt;
├── FUN_ram_054a7de0_ram_054a7de0.c         # ALLOC-dominant (67 KB)&lt;br /&gt;
├── FUN_ram_05723ef4_ram_05723ef4.c         # Tertiary dispatcher (13 KB)&lt;br /&gt;
├── FUN_ram_057a1ac0_ram_057a1ac0.c         # Primary dispatcher (558 B)&lt;br /&gt;
├── FUN_ram_057a1bcc_ram_057a1bcc.c ...     # 32 sub-commands (~550 B each)&lt;br /&gt;
├── FUN_ram_057e94ec_ram_057e94ec.c         # ALLOC main (40 KB)&lt;br /&gt;
├── FUN_ram_059be7f4_ram_059be7f4.c         # RPC jump table (4.9 KB)&lt;br /&gt;
├── FUN_ram_057664b7_ram_057664b7.c ...     # MAP/PIN/UNPIN/SCHED/YIELD/NOTIFY handlers&lt;br /&gt;
└── FUN_ram_057a22f8_ram_057a22f8.c ...     # 28 migration handlers&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== vGPU-IO Integration Checklist ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Management (ALLOC/FREE/MAP/UNMAP) ===&lt;br /&gt;
&lt;br /&gt;
* [ ] Implement kernel RPC client calling 0x057A1AC0&lt;br /&gt;
* [ ] Parse sub-command descriptors from 0x057A3AD8 jump table&lt;br /&gt;
* [ ] Hook ALLOC main at 0x057E94EC for vGPU memory carve-out&lt;br /&gt;
&lt;br /&gt;
=== Page Pinning (PIN/UNPIN) ===&lt;br /&gt;
&lt;br /&gt;
* [ ] Call secondary dispatcher PIN at 0x04ED34B8&lt;br /&gt;
* [ ] Implement UNPIN via 0x057682B7 / 0x05779FB7&lt;br /&gt;
&lt;br /&gt;
=== Scheduling (SCHEDULE/YIELD) ===&lt;br /&gt;
&lt;br /&gt;
* [ ] Use 0x05767F37 / 0x0575AEB7 / 0x051EFBF4 for vCPU scheduling&lt;br /&gt;
* [ ] Implement YIELD at 0x0575AE37 / 0x05767337&lt;br /&gt;
&lt;br /&gt;
=== BAR Emulation (BAR_TRAP) ===&lt;br /&gt;
&lt;br /&gt;
* [ ] Register handler at 0x04CB8188&lt;br /&gt;
* [ ] Emulate BAR1/Bar1Rest/ForceBarAccess/Bar1Aperture for VF&lt;br /&gt;
* [ ] Monitor 0x429B450 allocator for BAR backing store&lt;br /&gt;
&lt;br /&gt;
=== WPR Management ===&lt;br /&gt;
&lt;br /&gt;
* [ ] Hook completion callbacks from string refs (0x04F00B0C, 0x04F00C78)&lt;br /&gt;
* [ ] Implement NV_WPR_* notification forwarding to guest&lt;br /&gt;
* [ ] Manage WPR regions per-VF for isolation&lt;br /&gt;
&lt;br /&gt;
=== Migration (MIGRATE) ===&lt;br /&gt;
&lt;br /&gt;
* [ ] Implement dual jump table dispatch (0x04179ED8, 0x04179FBC)&lt;br /&gt;
* [ ] Handle 28 migration sub-commands&lt;br /&gt;
* [ ] Coordinate with guest VF live migration protocol&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Tools &amp;amp;amp; Scripts ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Script&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DecompileFunctions.java&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ghidra headless decompilation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;trace_all_subsystems.py&amp;lt;/code&amp;gt;&lt;br /&gt;
| Binary analysis: WPR/BAR/Migration strings, jump tables&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;gsp-fwimage-570.144/&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ghidra project directory&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ghidra Usage ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;/snap/ghidra/current/ghidra/support/analyzeHeadless \&lt;br /&gt;
  /path/to/project gsp-analysis \&lt;br /&gt;
  -import gsp-570.144.fwimage.bin \&lt;br /&gt;
  -noanalysis \&lt;br /&gt;
  -postScript DecompileFunctions.java \&lt;br /&gt;
  0xADDRESS1,0xADDRESS2,...&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* RPC map: [https://git.vgpu.io/open-iov.git/tree/firmware/57X-GSP/570.144/RPC_HANDLER_MAP.md &amp;lt;code&amp;gt;firmware/57X-GSP/570.144/RPC_HANDLER_MAP.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
* Final report: [https://git.vgpu.io/open-iov.git/tree/firmware/57X-GSP/570.144/FINAL_REPORT.md &amp;lt;code&amp;gt;firmware/57X-GSP/570.144/FINAL_REPORT.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
* Analysis results: [https://git.vgpu.io/open-iov.git/tree/firmware/57X-GSP/570.144/analysis_results.json &amp;lt;code&amp;gt;firmware/57X-GSP/570.144/analysis_results.json&amp;lt;/code&amp;gt;]&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=GMMU_Multi-Tenant_Protection&amp;diff=23969</id>
		<title>GMMU Multi-Tenant Protection</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=GMMU_Multi-Tenant_Protection&amp;diff=23969"/>
		<updated>2026-10-12T04:40:09Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= GMMU Multi-Tenant Protection =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Current — companion summary.''' This page condenses [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/14-multi-tenant-gmmu-protection.md &amp;lt;code&amp;gt;../docs/03-architecture/14-multi-tenant-gmmu-protection.md&amp;lt;/code&amp;gt;] (the canonical document: problem statement, full design, RM struct sketches, walked example, portability, M1–M8 roadmap). Read the canonical document for anything you intend to build against; this page is the quick map.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Open-IOV must isolate '''multiple mdevs (VMs)''' and, for multi-tenant inference, '''multiple tenants inside one guest''' at the GMMU. The design has two halves:&lt;br /&gt;
&lt;br /&gt;
# '''Service-state ownership (baseline 1.0).''' The work/completion service (&amp;lt;code&amp;gt;kernel/gsp_sema_service.c&amp;lt;/code&amp;gt;) is one global context (&amp;lt;code&amp;gt;static struct sema_svc svc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;:676&amp;lt;/code&amp;gt;), the pump services the first open mdev (&amp;lt;code&amp;gt;:13352-13364&amp;lt;/code&amp;gt;), and channels/VA spaces/translations are keyed by guest-chosen values alone (&amp;lt;code&amp;gt;:847&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;:988&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;:113-130&amp;lt;/code&amp;gt;). Two guests can pick the same handles and VAs (live: channel &amp;lt;code&amp;gt;0xcaf000d4&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;../debug/issue/issue-number-2.md&amp;lt;/code&amp;gt;), so owner-keying is a prerequisite for any GMMU policy.&lt;br /&gt;
# '''GMMU policy for paged attention (research).''' A tenant/agent-aware KV cache protection design across vLLM, a guest utility, RM controls, the vEP, and page tables — post-1.0, dual-gated; never a baseline dependency.&lt;br /&gt;
&lt;br /&gt;
== Isolation layers ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Layer&lt;br /&gt;
! Mechanism&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| L0 platform&lt;br /&gt;
| IOMMU/SMMU per-VM DMA, KVM memory/vCPU boundary&lt;br /&gt;
| live&lt;br /&gt;
|-&lt;br /&gt;
| L1 transport&lt;br /&gt;
| VFIO mdev per tenant, config/BAR/IRQ mediation&lt;br /&gt;
| live&lt;br /&gt;
|-&lt;br /&gt;
| L2 vEP state&lt;br /&gt;
| per-mdev emulation context + (needed) per-mdev work service&lt;br /&gt;
| live / design&lt;br /&gt;
|-&lt;br /&gt;
| L3 GMMU&lt;br /&gt;
| per-context page directory (VA space)&lt;br /&gt;
| live (guest-owned) / design (host-owned)&lt;br /&gt;
|-&lt;br /&gt;
| L4 arbitration&lt;br /&gt;
| channel ownership, TSG/runlist policy&lt;br /&gt;
| design&lt;br /&gt;
|-&lt;br /&gt;
| L5 completion&lt;br /&gt;
| owner-keyed release resolution; no cross-tenant apply&lt;br /&gt;
| wip&lt;br /&gt;
|-&lt;br /&gt;
| L6 fault&lt;br /&gt;
| fault attributed to the owning channel/tenant only&lt;br /&gt;
| wip&lt;br /&gt;
|-&lt;br /&gt;
| L7 application&lt;br /&gt;
| per-tenant/per-agent VA pooling inside a guest&lt;br /&gt;
| research&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Hardware primitives: proven vs hypothesis ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Primitive&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| 4-level tree, 49-bit VA, 4K/64K/2M pages, dual PDE0&lt;br /&gt;
| '''proven''' (&amp;lt;code&amp;gt;docs/43-GMMU-PTE-DECODER&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;kernel/gsp_sema_service.c:1058-1072&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| VER2 PTE fields incl. &amp;lt;code&amp;gt;read_only&amp;lt;/code&amp;gt; (6), &amp;lt;code&amp;gt;privilege&amp;lt;/code&amp;gt; (5), &amp;lt;code&amp;gt;encrypted&amp;lt;/code&amp;gt; (4), &amp;lt;code&amp;gt;kind&amp;lt;/code&amp;gt;&lt;br /&gt;
| '''proven format''' (&amp;lt;code&amp;gt;docs/43&amp;lt;/code&amp;gt; §3)&lt;br /&gt;
|-&lt;br /&gt;
| Separate page directory per VA space (&amp;lt;code&amp;gt;SET_PAGE_DIRECTORY&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;hVASpace&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;chId&amp;lt;/code&amp;gt;)&lt;br /&gt;
| '''proven''' (&amp;lt;code&amp;gt;kernel/gsp_rm_emulation.c:3310-3314&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| No tenant/ACL/PASID field in the VER2 PTE/PDE&lt;br /&gt;
| '''proven absence''' in the field catalogue&lt;br /&gt;
|-&lt;br /&gt;
| RO-leaf write enforcement&lt;br /&gt;
| '''hypothesis''' (needs a supervised probe; M7)&lt;br /&gt;
|-&lt;br /&gt;
| Encryption-domain (CCS) as a tenant boundary&lt;br /&gt;
| '''hypothesis'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== The design in brief ==&lt;br /&gt;
&lt;br /&gt;
* '''Design A (stock-compatible).''' Extended vLLM reserves a VA range per agent; a new guest utility (&amp;lt;code&amp;gt;oiv-agentd&amp;lt;/code&amp;gt;) publishes tag records to a device-memory '''tag mailbox''' the vEP can read (emulation mode: guest vidmem is host RAM, &amp;lt;code&amp;gt;kernel/bar_init.c:68-77&amp;lt;/code&amp;gt;). The vEP enforces owner↔VA-subtree match at map time and at submit time. No guest KMD change. Research (M6).&lt;br /&gt;
* '''Design B (explicit controls).''' New vGPU-private RM controls — &amp;lt;code&amp;gt;TENANT_BIND&amp;lt;/code&amp;gt; (0x90f10120), &amp;lt;code&amp;gt;TAG_RANGE&amp;lt;/code&amp;gt; (…21), &amp;lt;code&amp;gt;UNTAG_RANGE&amp;lt;/code&amp;gt; (…22), &amp;lt;code&amp;gt;TENANT_SHARE&amp;lt;/code&amp;gt; (…23), &amp;lt;code&amp;gt;AGENT_CHANNEL_BIND&amp;lt;/code&amp;gt; (…24), &amp;lt;code&amp;gt;TAG_QUERY&amp;lt;/code&amp;gt; (…25) — plus struct sketches in the canonical doc §4.5. Requires a guest KMD extension: post-1.0, gated (M8).&lt;br /&gt;
* '''Granularities.''' Per-KV-block tagging (finest; software+PTE policy, sharing needs RO enforcement); per-tenant separate page directories (the only proven hardware lever); per-agent separate channels (fault/QoS containment; optional per-agent sub-directories). Degradation ladder and per-granularity cost/failure analysis in canonical §4.7.&lt;br /&gt;
&lt;br /&gt;
== Walked example (two tenants, paged_attention_v2) ==&lt;br /&gt;
&lt;br /&gt;
Two agents A1/A2 each own a VA pool and channels. A malicious T1 kernel naming an A2 VA hits a missing PTE (GMMU fault) and/or is refused by vEP submit-time policy; the fault is attributed to A1 only (T2 untouched); a periodic owner-vs-PTE audit with canaries catches escapes. If only per-tenant separation exists, the deployable contract is '''one agent per tenant, one tenant per context''' (canonical §5.4).&lt;br /&gt;
&lt;br /&gt;
== Key code anchors (master &amp;lt;code&amp;gt;1f571dda&amp;lt;/code&amp;gt;) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! What&lt;br /&gt;
! Where&lt;br /&gt;
|-&lt;br /&gt;
| per-mdev emulation context&lt;br /&gt;
| &amp;lt;code&amp;gt;kernel/include/nvidia-vgpu-vfio.h:133&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;kernel/gsp_emulation.h:130&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| global service state&lt;br /&gt;
| &amp;lt;code&amp;gt;kernel/gsp_sema_service.c:676&amp;lt;/code&amp;gt;; pump &amp;lt;code&amp;gt;:13352&amp;lt;/code&amp;gt;; doorbell &amp;lt;code&amp;gt;:13512&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| channel/vaspace registries&lt;br /&gt;
| &amp;lt;code&amp;gt;kernel/gsp_sema_service.c:847&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;:988&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| GMMU walk (VER2)&lt;br /&gt;
| &amp;lt;code&amp;gt;kernel/gsp_sema_service.c:1174&amp;lt;/code&amp;gt;; decode &amp;lt;code&amp;gt;:1093&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| page directory record&lt;br /&gt;
| &amp;lt;code&amp;gt;kernel/gsp_rm_emulation.c:3320&amp;lt;/code&amp;gt;; reserved PDEs &amp;lt;code&amp;gt;:2237-2262&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| per-mdev FB sizing&lt;br /&gt;
| &amp;lt;code&amp;gt;kernel/bar_init.c:60-77&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;kernel/include/ioctl.h:39-46&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| L2 invalidate acked&lt;br /&gt;
| &amp;lt;code&amp;gt;kernel/gsp_rm_emulation.c:2519-2532&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Roadmap (acceptance criteria in canonical §7.3) ==&lt;br /&gt;
&lt;br /&gt;
M1 per-mdev service state — M2 two-guest isolation gate — M3 per-mdev real GSP clients + fairness — M4 independent VRAM sizes/sparse backing — M5 invalidate + eviction/reclaim (I1–I6 invariants) — M6 Design A prototype — M7 RO/permission probe — M8 Design B / CCS / 610 (gated). M1–M5 are the 1.0 programme; M6–M8 are post-1.0 research, dual-gated, duplicate-not- replace, never required by the baseline. RM 610 stays behind its own human gate (&amp;lt;code&amp;gt;docs/23-RM610-READINESS&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]] — from-first-principles GMMU introduction (what it is, page tables, IOMMU/MMU/SMMU relationships)&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/14-multi-tenant-gmmu-protection.md &amp;lt;code&amp;gt;../docs/03-architecture/14-multi-tenant-gmmu-protection.md&amp;lt;/code&amp;gt;] — canonical&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/13-vexecution-plane.md &amp;lt;code&amp;gt;../docs/03-architecture/13-vexecution-plane.md&amp;lt;/code&amp;gt;] — vEP vocabulary (parallel)&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/05-gmmu-amap-hal-gr.md &amp;lt;code&amp;gt;../docs/03-architecture/05-gmmu-amap-hal-gr.md&amp;lt;/code&amp;gt;] — GMMU background&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/09-full-system-picture.md &amp;lt;code&amp;gt;../docs/03-architecture/09-full-system-picture.md&amp;lt;/code&amp;gt;] — multi-tenancy and isolation map&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/11-physical-backend-guest-wiring.md &amp;lt;code&amp;gt;../docs/03-architecture/11-physical-backend-guest-wiring.md&amp;lt;/code&amp;gt;] — forwarding and page-table seams&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/05-operations/01-performance-correctness-security.md &amp;lt;code&amp;gt;../docs/05-operations/01-performance-correctness-security.md&amp;lt;/code&amp;gt;] — threat model, rung 5&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/debug/issue/issue-number-2.md &amp;lt;code&amp;gt;../debug/issue/issue-number-2.md&amp;lt;/code&amp;gt;] — per-client state wedge&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md &amp;lt;code&amp;gt;../debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md&amp;lt;/code&amp;gt;] — GMMU field catalogue&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=FAQ&amp;diff=23968</id>
		<title>FAQ</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=FAQ&amp;diff=23968"/>
		<updated>2026-10-12T04:40:08Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= FAQ =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' The questions the project is asked most, answered honestly and with pointers to the maintained documents. Condensed from [https://git.vgpu.io/open-iov.git/tree/docs/09-reference/glossary-and-faq.md &amp;lt;code&amp;gt;../docs/09-reference/glossary-and-faq.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Project and positioning ==&lt;br /&gt;
&lt;br /&gt;
'''Is this a replacement for vLLM on bare metal?''' No. Continuous batching on a bare-metal host is the right answer for centralized inference, and it stays that way. Open-IOV is for compute ''inside guests'': Linux and Windows CUDA, 3D, video, and secure edge isolation.&lt;br /&gt;
&lt;br /&gt;
'''Does the guest driver need to be patched?''' No, and that is a hard project rule: no guest driver patches, no host driver patches, no firmware patches, no hypervisor patches. The guest runs the stock NVIDIA driver, unmodified.&lt;br /&gt;
&lt;br /&gt;
'''Does the host driver need to be patched or replaced?''' No. In the standalone configuration the distribution driver owns the physical GPU and Open-IOV is an independent kernel module. Building NVIDIA's OpenRM modules from source is needed only for the native vGPU-management workflows, not for the QEMU/emulated path ([[Install and First Run|&amp;lt;code&amp;gt;Install-and-First-Run.md&amp;lt;/code&amp;gt;]] §2).&lt;br /&gt;
&lt;br /&gt;
'''Why is &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; working but my CUDA kernel not running?''' Because execution is the frontier, not the setup. Today, a stock guest driver probes, &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; works, device enumeration works, and the full CUDA '''driver-API''' path (context creation, allocation, copies, free, destroy) completes; a guest '''kernel launch''' is forwarded to the physical engine queue but the engine does not yet execute the forwarded launch descriptor (&amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt;). This is the project's known status, not a misconfiguration — see [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] and [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
'''How fast is it?''' No published numbers yet. Copy-engine-class forwarding and its completion and fault relay are implemented (default off) and GR execution is the open frontier; even the initialization path has not yet been measured under the project's methodology. Any performance claim will ship together with its methodology and measurements.&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
'''Will it support Windows guests?''' Yes, it is a target: same architecture, measured bring-up. [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]] lists the support ladder.&lt;br /&gt;
&lt;br /&gt;
'''Can I run several VMs on one GPU?''' That is a core design goal: one mediated device per VM, IOMMU isolation, and explicit scheduling at the GPU's memory-management unit. Multi-tenant maturity depends on the scheduling and isolation work tracked in the project's known-unknowns document.&lt;br /&gt;
&lt;br /&gt;
'''Does it support Xen / Qubes OS Air / Argo / OpenXT?''' Designed for them. The emulation core is hypervisor-independent by construction; the transport backends are on the roadmap. KVM/QEMU with VFIO mdev is the reference transport today.&lt;br /&gt;
&lt;br /&gt;
'''What about MIG?''' MIG is a hardware partitioning mechanism; the project's scheduling policy can use it where available. It is part of the multi-tenancy work.&lt;br /&gt;
&lt;br /&gt;
'''Which GPUs are supported?''' Turing TU104 is the reference platform. Other generations are targets or experimental combinations — see [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]] for the exact ladder and what each status means.&lt;br /&gt;
&lt;br /&gt;
== Legal and licensing ==&lt;br /&gt;
&lt;br /&gt;
'''How is this legal / license-clean?''' Open-IOV's own code is BSD-3-Clause (GPL-2.0 for the kernel modules that link GPL-only kernel exports); NVIDIA's software is used unmodified and is not redistributed. The project interoperates with the interfaces rather than relicensing anything. Details: the repository &amp;lt;code&amp;gt;LICENSE&amp;lt;/code&amp;gt; and the legal reference in &amp;lt;code&amp;gt;docs/09-reference/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Can my company use this commercially?''' Yes, under BSD-3-Clause (kernel modules GPL-2.0), with no fee. Co-development is welcome — see [[HAAEEP and Collaboration|&amp;lt;code&amp;gt;HAAEEP-and-Collaboration.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
== Contributing ==&lt;br /&gt;
&lt;br /&gt;
'''Where do I report bugs or ask for help?''' Open an issue in the repository with a reproduction and the standard captures (host dmesg, guest dmesg, guest &amp;lt;code&amp;gt;lspci -vvv&amp;lt;/code&amp;gt;, guest driver parameters). A reproduction plus logs is worth more than a description.&lt;br /&gt;
&lt;br /&gt;
'''How do I contribute support for my GPU / driver / hypervisor?''' Start from [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]] and the portability workflow in the repository. The deliverable is a profile plus evidence from the project's evaluation ladder.&lt;br /&gt;
&lt;br /&gt;
'''How do I debug the firmware side?''' The risc-v-gsp-rm-debugger workbench runs GSP firmware in a RISC-V virtual machine with hooks, watchpoints and recorded sessions — [[risc-v-gsp-rm-debugger|&amp;lt;code&amp;gt;Riscv-GSP-RM-Debugger.md&amp;lt;/code&amp;gt;]].&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=The_vGSP_Execution_Plane_(vEP)&amp;diff=23967</id>
		<title>The vGSP Execution Plane (vEP)</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=The_vGSP_Execution_Plane_(vEP)&amp;diff=23967"/>
		<updated>2026-10-12T04:40:08Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= The vGSP Execution Plane (vEP) =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Canonical, maintained version of this page:''' [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/13-vexecution-plane.md &amp;lt;code&amp;gt;../docs/03-architecture/13-vexecution-plane.md&amp;lt;/code&amp;gt;]. This wiki page is the condensed public deep-dive: what the layer is, how a guest CUDA launch flows through it, where it stands today, and where it is going. It is condensed from the canonical document and its cited evidence; when the two disagree, the docs tree wins. Front door: [https://git.vgpu.io/open-iov.git/tree/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-08, tree &amp;lt;code&amp;gt;master @ 1f571dda&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; proven with the stock guest driver; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented, default-off or parameter-gated; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partial; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; current blocker; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; named success latch; &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; designed, not built.&lt;br /&gt;
&lt;br /&gt;
== 1. What it is ==&lt;br /&gt;
&lt;br /&gt;
'''vGSP (virtual GSP)''' is our host-side reimplementation of the GPU System Processor interface: the virtual device plus the emulated GSP-RM service the stock guest driver talks to, implemented by &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt;. The '''vGSP Execution Plane (vEP)''' is the half of vGSP that turns guest-authored GPU work into physical execution and guest-visible completion: channel ring and USERD discovery, GPU VA-to-PA truth, semaphore-release application, completion counters and notifiers, QMD handling for forwarded launches, and submission to the physical GPU's engines under the module-owned backend session.&lt;br /&gt;
&lt;br /&gt;
The other half — the control plane (boot handshake, message queues, RPC, RM objects, BAR shadows) — makes the guest driver ''run''. The vEP makes the guest's work ''run''. The canonical document defines the name and rejects the alternates (&amp;quot;work plane&amp;quot;, &amp;quot;submission plane&amp;quot;, &amp;quot;forwarding plane&amp;quot;, ...) that would collide with existing project vocabulary.&lt;br /&gt;
&lt;br /&gt;
'''Four work domains''' organize the subsystem:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Domain&lt;br /&gt;
! Question&lt;br /&gt;
! Implemented by&lt;br /&gt;
|-&lt;br /&gt;
| Scheduler&lt;br /&gt;
| which channel's work runs, at what pace&lt;br /&gt;
| doorbell steering, the per-channel pump, discovery cadence, one ordered workqueue, one in-flight request&lt;br /&gt;
|-&lt;br /&gt;
| Allocator&lt;br /&gt;
| where rings, USERDs, counters, notifiers and scratch windows live&lt;br /&gt;
| ring/USERD autopin and pins, content-keyed pairing, counter derive, ladder scratch/PT pools, the BAR1 vidmem shadow&lt;br /&gt;
|-&lt;br /&gt;
| Control&lt;br /&gt;
| which RM objects/controls shape execution&lt;br /&gt;
| channel and event registration, &amp;lt;code&amp;gt;SET_PAGE_DIRECTORY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PROMOTE_CTX&amp;lt;/code&amp;gt;, engine topology, the mode matrix&lt;br /&gt;
|-&lt;br /&gt;
| Share&lt;br /&gt;
| how clients/mdevs share the one GPU&lt;br /&gt;
| mdev backend refcount, one real session under a single lock, one workqueue; per-mdev clients and fairness are planned&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 2. The shape of the plane ==&lt;br /&gt;
&lt;br /&gt;
[[File:The-vGSP-Execution-Plane-diagram.png|frameless|center|upright=2.2|The vGSP execution plane (vEP): one CUDA launch, end to end.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;guest: push + QMD + GPFIFO entry + doorbell (BAR0 0x88704)&lt;br /&gt;
  -&amp;amp;gt; pump (per-channel) -&amp;amp;gt; ring/USERD discovery -&amp;amp;gt; VA-to-PA truth -&amp;amp;gt; decode&lt;br /&gt;
  -&amp;amp;gt; release apply + counter publish + notifier/event -&amp;amp;gt; MSI-X -&amp;amp;gt; guest wakes&lt;br /&gt;
  -&amp;amp;gt; (for real work) ordered workqueue -&amp;amp;gt; ladder submission -&amp;amp;gt; real GSP/engines&lt;br /&gt;
  -&amp;amp;gt; engine-authored release -&amp;amp;gt; poll -&amp;amp;gt; completion publication&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. One CUDA kernel launch, end to end ==&lt;br /&gt;
&lt;br /&gt;
# '''Launch build (guest).''' &amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt; build the GR push: context methods, the inline launch descriptor (QMD), SASS and parameter pointers, and a release target. They append a GPFIFO entry and ring the BAR0 doorbell. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed with the stock driver.&lt;br /&gt;
# '''Steering and truth (host).''' The doorbell wakes the service thread; the pump resolves the channel's ring VA and USERD, reads &amp;lt;code&amp;gt;GP_PUT&amp;lt;/code&amp;gt;, fetches the GPFIFO entry and decodes the method stream. Translations are read-back proven from driver-published page directories, pins, or content-rescue. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; for CE; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; for GR (discovery now succeeds, see §4).&lt;br /&gt;
# '''Capture.''' The decoder accumulates the QMD window and captures the launch candidate; the sema service queues one request on the single ordered workqueue. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed (ring consumed, methods execute).&lt;br /&gt;
# '''Physical submit.''' The backend relocates the QMD, copies program/param pages into module shadow windows whose PTEs were planted before the channel commit (the engine never sees a late PTE write — it caches 128-byte fetch lines with no invalidate), builds the launch method block, publishes it to the ladder channel's GPFIFO and rings the real doorbell. &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; default-off; latched on a proven real GR submission.&lt;br /&gt;
# '''Engine.''' The front-end fetches the entry and executes methods; then the '''inline-QMD install''' must materialise the descriptor for the engine to read, currently '''&amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt;''' — not observed. Context validity, destination mapping and fetch/alignment are exonerated; the recovered-method-stream form is the investigation.&lt;br /&gt;
# '''Completion.''' The engine authors the QMD release word and the channel release; the host applies the deferred release exactly once, publishes the completion counter, clears the notifier and posts the channel event; MSI-X wakes the guest. CE work is live in this shape &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt;; for GR the completion-counter publication is the current second face of the wall.&lt;br /&gt;
&lt;br /&gt;
== 4. How work is found: discovery, truth, completion ==&lt;br /&gt;
&lt;br /&gt;
* '''Ring/USERD discovery''' has three cooperating sources: injected pins, a kernel-native trusted walk of driver-published page directories, and content-keyed discovery when neither names the ring. Content discovery scans '''both apertures''' (emulated vidmem and guest RAM), runs the FB scan first on a 2-second cadence, pairs a ring with the rank's staged ctx-init push, and validates the pair before pinning. Since the 2026-10-08 re-arm work (&amp;lt;code&amp;gt;7abd8f87&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;66388560&amp;lt;/code&amp;gt;) the discovery no longer retires permanently at a pass cap.&lt;br /&gt;
* '''The semaphore service''' decodes releases, translates their target pages through the trusted resolver plus a driver-published-VAS pool resolver, defers untranslatable releases with retry telemetry, and applies each release exactly once — in software, or by letting the engine author it under the relay (default off).&lt;br /&gt;
* '''Completion counters''' use a fixed 20-slot pool (a partial live channel count poisoned slots before the fix); each decoded release lands in the channel's exact slot. '''Notifiers''' are serviced by the pump, and family events are delivered as RM events + MSI-X through the guest's registered event objects.&lt;br /&gt;
&lt;br /&gt;
== 5. Challenges, honestly ==&lt;br /&gt;
&lt;br /&gt;
* '''GR dispatch wall.''' The forward path runs front-end methods, the context is valid and the destination window is accepted — and the descriptor install is still not observed. The mode matrix carries dozens of single-variable falsifiers (promote shapes, prelude/PCAS form, local-memory block, lane controls, shadow windows, pointer relocation).&lt;br /&gt;
* '''Completion publication.''' A boot where GR rings were discovered and releases applied still saw the guest re-queue the same push and give up. A later &amp;lt;code&amp;gt;sema_dbg=Y&amp;lt;/code&amp;gt; run settled it: the release was written to the exact slot, the notifier cleared and the event posted, while the completion counter publication never wrote because the fixed-total autoreg mapping makes it a structural no-op. The leading reading is the counter-slot publication; the GP_GET write-back is the secondary, still-open candidate. Both are debug-gated today.&lt;br /&gt;
* '''Reproducibility (ISSUE-0001).''' The green/stall split is per-boot. The first fix wave landed and the earlier CE freeze is gone; the stall moved to GR ring discovery, which the latest discovery work addresses. Acceptance is 10 cold boots green, pending.&lt;br /&gt;
* '''Multiple clients (ISSUE-0002).''' A second CUDA process wedges in guest UVM because host per-client sema/GR state is not reset when the guest re-runs its per-client boot handshake. Per-client state containers and reset are the designed path.&lt;br /&gt;
&lt;br /&gt;
== 6. Portability ==&lt;br /&gt;
&lt;br /&gt;
The '''architecture''' ports: observe pushes, resolve truth, decode, execute/forward, publish completion. So does the '''RPC/RM object model''' and the mode-matrix practice. What does '''not''' port is address-level fact: ring conventions, VA windows, QMD offsets, context-image layout, PTE encodings, engine inventories and scratch layouts must be re-derived per driver version and GPU architecture by measurement, never guessed. A new version enters as a profile plus a measured delta; driver 610 additionally sits behind an explicit human approval gate.&lt;br /&gt;
&lt;br /&gt;
== 7. Future ==&lt;br /&gt;
&lt;br /&gt;
The planned next steps are reproducibility acceptance, the descriptor-install and completion-publication investigations (offline-first with the RISC-V GSP-RM debugger where possible), the arbitrary-kernel acceptance suite, then the near-native performance program. The unsolved future classes — multi-tenant fairness, fault replay/cancel, context switching between tenants, hostile-guest hardening, and version drift — each have a proactive design direction in the canonical document. 3D graphics reuses this pipeline once compute dispatch is proven; it adds engine breadth (video/image), more channels and synchronisation volume, and a much larger method vocabulary, but not a new plane.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
''Canonical document: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/13-vexecution-plane.md &amp;lt;code&amp;gt;docs/03-architecture/13-vexecution-plane.md&amp;lt;/code&amp;gt;]. See also: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/09-full-system-picture.md full system picture], [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/11-physical-backend-guest-wiring.md physical backend guest wiring], [https://git.vgpu.io/open-iov.git/tree/docs/04-implementation/03-execution-frontier.md the execution frontier].''&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=The_Execution_Frontier&amp;diff=23966</id>
		<title>The Execution Frontier</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=The_Execution_Frontier&amp;diff=23966"/>
		<updated>2026-10-12T04:40:07Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= The Execution Frontier =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' The current leading edge of guest-facing execution: the chain that must fire for a stock guest CUDA kernel to run on the physical GPU, what has been proven about it, where it stops, how we know, and the open lines of investigation and theories. It is evidence-led: every statement carries a live observation, a decompilation finding, or a clearly labelled theory. Condensed from [https://git.vgpu.io/open-iov.git/tree/docs/04-implementation/03-execution-frontier.md &amp;lt;code&amp;gt;../docs/04-implementation/03-execution-frontier.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12 (source page dated 2026-10-06), tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partial; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; current blocker; theories are labelled as such.&lt;br /&gt;
&lt;br /&gt;
== 1. The chain that should fire ==&lt;br /&gt;
&lt;br /&gt;
A guest CUDA launch becomes a '''method stream''' in a push buffer, referenced by a '''GPFIFO ring entry''', announced by a '''doorbell'''. The host emulation decodes it and forwards an equivalent method stream to a real channel owned by the module's resource-manager session. The hardware '''front-end''' fetches and executes the methods, the launch descriptor ('''QMD''') is materialised and read by the '''GR engine''', the grid is dispatched to the SMs, and completion is published as '''semaphores''' the guest waits on.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;guest: builds launch + method stream&lt;br /&gt;
       GPFIFO entry + doorbell&lt;br /&gt;
   -&amp;amp;gt; host: doorbell trap, decode, rebuild forward stream,&lt;br /&gt;
            prewrite QMD, ring/USERD, doorbell&lt;br /&gt;
   -&amp;amp;gt; front-end: fetch GPFIFO entry (ring cursor advances)&lt;br /&gt;
   -&amp;amp;gt; front-end: execute methods (object bind, cache ops, report sem)&lt;br /&gt;
   -&amp;amp;gt; front-end: install inline QMD into the descriptor buffer&lt;br /&gt;
   -&amp;amp;gt; GR engine: read QMD through the channel's page tables&lt;br /&gt;
   -&amp;amp;gt; context switch loads the channel context (FECS/ucode)&lt;br /&gt;
   -&amp;amp;gt; GR: dispatch grid to the SMs&lt;br /&gt;
   -&amp;amp;gt; engine authors release semaphore + channel semaphore&lt;br /&gt;
   -&amp;amp;gt; host polls release, relays to guest; CUDA wakes&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! #&lt;br /&gt;
! Stage&lt;br /&gt;
! State&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Guest builds launch + method stream&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed (stock driver, unmodified)&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| GPFIFO entry + doorbell&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Host decode + forward stream + QMD prewrite + ring/USERD&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Front-end fetches the ring entry&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed (ring cursor advances)&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Front-end executes methods&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed (object bind, cache ops, report semaphore)&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| '''Inline-QMD install''' (descriptor materialised)&lt;br /&gt;
| &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; not observed&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| '''Engine reads the QMD'''&lt;br /&gt;
| &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; not observed&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Context switch loads the channel context&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; context validity at dispatch is ruled in&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| GR dispatches the grid to the SMs&lt;br /&gt;
| never observed on this stack&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Engine authors release + channel semaphore&lt;br /&gt;
| absent for forwarded launches&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Host relays completion; guest wakes&lt;br /&gt;
| the guest waits and times out&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''One-line summary:''' the guest, the emulation, the forwarding path and the front-end are live; the '''launch-descriptor install path''' (stages 6–7) is the leading edge, and with it stages 9–11.&lt;br /&gt;
&lt;br /&gt;
== 2. Where the leading edge is ==&lt;br /&gt;
&lt;br /&gt;
A stock guest program now reaches its kernel launch and submits it through the forwarding path. On the wire the ring entry is consumed and the front-end methods run — but the launch descriptor is never materialised, the engine never reads a QMD, no engine-authored completion appears, and the guest blocks in its synchronisation wait.&lt;br /&gt;
&lt;br /&gt;
This is '''not''' a context-validity wall (ruled out at dispatch) and '''not''' a window-mapping wall for the descriptor destination (that install is accepted). The wall is the '''form of the launch method stream''': what the front-end requires in order to install the inline descriptor, and what the engine requires in order to read and dispatch it.&lt;br /&gt;
&lt;br /&gt;
== 3. How we know (observables and their limits) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Observable&lt;br /&gt;
! What it proves&lt;br /&gt;
! What it does not prove&lt;br /&gt;
|-&lt;br /&gt;
| Ring entry consumed; ring cursor advances&lt;br /&gt;
| the front-end is alive and fetching&lt;br /&gt;
| nothing about the engine&lt;br /&gt;
|-&lt;br /&gt;
| Method execution on the ladder channel&lt;br /&gt;
| the front-end can execute the method vocabulary&lt;br /&gt;
| '''not''' engine execution — these signals can be front-end-authored&lt;br /&gt;
|-&lt;br /&gt;
| Descriptor buffer prewritten with a detectable sentinel&lt;br /&gt;
| whether the descriptor was materialised after submission&lt;br /&gt;
| a read does not modify memory; the sentinel detects installs, not reads&lt;br /&gt;
|-&lt;br /&gt;
| Install sentinel unchanged after submit&lt;br /&gt;
| the inline-install method did not run&lt;br /&gt;
| it does not say why&lt;br /&gt;
|-&lt;br /&gt;
| Engine-authored release word absent; poll times out&lt;br /&gt;
| the engine did not complete the launch&lt;br /&gt;
| it does not say whether the engine started&lt;br /&gt;
|-&lt;br /&gt;
| No GR fault recorded&lt;br /&gt;
| the engine did not raise this error&lt;br /&gt;
| silence is not health: a skipped launch is silent by construction&lt;br /&gt;
|-&lt;br /&gt;
| Channel instance context flag set&lt;br /&gt;
| the channel is context-valid at dispatch&lt;br /&gt;
| nothing about the descriptor path&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Consequence:''' progress on this frontier must be measured by an '''engine-authored''' signal (the release word advancing) — not by front-end signals, which we have already learned to distinguish.&lt;br /&gt;
&lt;br /&gt;
== 4. What is exonerated (do not relitigate) ==&lt;br /&gt;
&lt;br /&gt;
* Context validity at dispatch — the channel's context is valid when the launch is submitted (instance flag set).&lt;br /&gt;
* The descriptor destination window mapping — installed in the engine's table view at submit.&lt;br /&gt;
* Front-end fetch and control-block alignment — the entry is consumed with the host control block at offset 0.&lt;br /&gt;
* The shared context-buffer one-shot rule — traced to a shared per-GPU buffer already initialised in the same cycle; not the dispatch delta.&lt;br /&gt;
* Parenting/TSG for the fetch — both variants fetch identically.&lt;br /&gt;
* The copy-engine path — CE-class work, releases and fault relay are live (default off); the GR path is a separate problem.&lt;br /&gt;
&lt;br /&gt;
== 5. The clear issues (ranked) ==&lt;br /&gt;
&lt;br /&gt;
'''Issue A — the forwarded stream carries a verbatim guest prelude that cannot complete.''' The forwarded stream includes a verbatim copy of the guest's prelude whose inline-data writes target addresses not present in the engine's view of the channel's page tables, and the referenced data is not relocated. The shorter, proven stream shape fires its tail (channel semaphore) but still does not schedule the descriptor.&lt;br /&gt;
&lt;br /&gt;
'''Issue B — the descriptor-virtualization control method is absent.''' The method that arms the inline-descriptor install path is not present in the forwarded stream. Fixing it should materialise the descriptor — falsifiable in one cycle by watching the sentinel and the engine-read signal.&lt;br /&gt;
&lt;br /&gt;
'''Issue C — diagnostic hygiene.''' The sentinel placed at word 0 overlaps real descriptor fields; it must be moved to an unused word so diagnostics do not perturb what they measure.&lt;br /&gt;
&lt;br /&gt;
== 6. Lines of investigation (live) ==&lt;br /&gt;
&lt;br /&gt;
# '''Restore the proven launch shape''' as the baseline and '''re-add the virtualization control method''' — one variable at a time, with the install sentinel and the engine-read signal as the readout.&lt;br /&gt;
# '''Relocate or drop the verbatim prelude''' so inline-data writes target addresses present in the engine's view, or replace it with the host-side staging the proven shape already uses.&lt;br /&gt;
# '''Move the sentinel''' and re-run to confirm the readout is clean.&lt;br /&gt;
# '''Diff against a known-good reference''' — our own ladder dispatching a descriptor built from the same source material, or a captured working launch of the stock stack on the same GPU — converting the remaining work from inference to differential.&lt;br /&gt;
# '''Offline probing''' of any rule the front-end or engine is believed to require, using the firmware debugger before spending a supervised cycle ([[risc-v-gsp-rm-debugger|&amp;lt;code&amp;gt;Riscv-GSP-RM-Debugger.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 7. Theories (labelled; not yet proven) ==&lt;br /&gt;
&lt;br /&gt;
* '''T1 — the virtualization control is the gate.''' The front-end will not materialise an inline descriptor until the control method enables the install path.&lt;br /&gt;
* '''T2 — materialise-then-read.''' The engine only schedules a descriptor that exists in its own view; an install targeting unmapped destinations aborts silently rather than faulting.&lt;br /&gt;
* '''T3 — the verbatim prelude poisons the launch.''' Its refused writes leave the launch path unable to schedule the descriptor.&lt;br /&gt;
* '''T4 — relocation is the missing transform.''' The guest's descriptor is valid for the guest's view of memory; the forwarding path must relocate referenced data into the channel's view before install.&lt;br /&gt;
&lt;br /&gt;
Each theory has a one-cycle falsifier: the install sentinel, the engine-read signal, and the engine-authored release, in that order.&lt;br /&gt;
&lt;br /&gt;
== 8. Claim discipline ==&lt;br /&gt;
&lt;br /&gt;
* '''Engine-authored release is the only proof of execution.''' Front-end signals are necessary but not sufficient.&lt;br /&gt;
* '''Silence is not health.''' No fault recorded does not mean no fault occurred.&lt;br /&gt;
* '''Emulator verdicts are instruction/memory-level.''' They bound behaviour, never timing or device environment.&lt;br /&gt;
* '''A wall is closed only by an acceptance signal''', named before the experiment.&lt;br /&gt;
&lt;br /&gt;
== 9. Related pages ==&lt;br /&gt;
&lt;br /&gt;
* [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] — the project-level ladder.&lt;br /&gt;
* [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]] — the guest-side client path.&lt;br /&gt;
* [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]] — the backend the work is forwarded to.&lt;br /&gt;
* [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]] — the execution layer's design.&lt;br /&gt;
* [[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]] — page tables, QMDs and the engines.&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/04-implementation/03-execution-frontier.md &amp;lt;code&amp;gt;../docs/04-implementation/03-execution-frontier.md&amp;lt;/code&amp;gt;] — the canonical, continuously-updated version with the full evidence tables.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Error_Codes&amp;diff=23965</id>
		<title>Error Codes</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Error_Codes&amp;diff=23965"/>
		<updated>2026-10-12T04:40:07Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= GSP Error Codes =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' The GSP-specific POSIX-style names in this page are historical labels from early reverse engineering, not wire statuses. The emulation uses NVIDIA &amp;lt;code&amp;gt;NV_STATUS&amp;lt;/code&amp;gt; values: &amp;lt;code&amp;gt;NV_OK&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;NV_ERR_NOT_SUPPORTED&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;0x56&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;NV_ERR_INVALID_PARAMETER&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;0x3B&amp;lt;/code&amp;gt;. Canonical reference: [https://git.vgpu.io/open-iov.git/tree/docs/09-reference/glossary-and-faq.md &amp;lt;code&amp;gt;../docs/09-reference/glossary-and-faq.md&amp;lt;/code&amp;gt;] and the kernel's &amp;lt;code&amp;gt;NV_STATUS&amp;lt;/code&amp;gt; usage (&amp;lt;code&amp;gt;../kernel/&amp;lt;/code&amp;gt;).&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Standard POSIX Errors (Negative Return Values) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Hex&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x00000000&lt;br /&gt;
| OK&lt;br /&gt;
| Success&lt;br /&gt;
|-&lt;br /&gt;
| -1&lt;br /&gt;
| 0xFFFFFFFF&lt;br /&gt;
| EPERM&lt;br /&gt;
| Operation not permitted&lt;br /&gt;
|-&lt;br /&gt;
| -2&lt;br /&gt;
| 0xFFFFFFFE&lt;br /&gt;
| ENOENT&lt;br /&gt;
| No such file/entry&lt;br /&gt;
|-&lt;br /&gt;
| -3&lt;br /&gt;
| 0xFFFFFFFD&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Invalid argument&lt;br /&gt;
|-&lt;br /&gt;
| -6&lt;br /&gt;
| 0xFFFFFFFA&lt;br /&gt;
| ENODEV&lt;br /&gt;
| No such device&lt;br /&gt;
|-&lt;br /&gt;
| -12&lt;br /&gt;
| 0xFFFFFFF4&lt;br /&gt;
| ENOMEM&lt;br /&gt;
| Out of memory&lt;br /&gt;
|-&lt;br /&gt;
| -16&lt;br /&gt;
| 0xFFFFFFEE&lt;br /&gt;
| EBUSY&lt;br /&gt;
| Device/resource busy&lt;br /&gt;
|-&lt;br /&gt;
| -22&lt;br /&gt;
| 0xFFFFFFEA&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Invalid argument&lt;br /&gt;
|-&lt;br /&gt;
| -28&lt;br /&gt;
| 0xFFFFFFE4&lt;br /&gt;
| ENOSPC&lt;br /&gt;
| No space left on device&lt;br /&gt;
|-&lt;br /&gt;
| -37&lt;br /&gt;
| 0xFFFFFFDB&lt;br /&gt;
| ENOLCK&lt;br /&gt;
| No locks available&lt;br /&gt;
|-&lt;br /&gt;
| -56&lt;br /&gt;
| 0xFFFFFFC8&lt;br /&gt;
| EBADMSG&lt;br /&gt;
| Bad message&lt;br /&gt;
|-&lt;br /&gt;
| -84&lt;br /&gt;
| 0xFFFFFFAC&lt;br /&gt;
| EOVERFLOW&lt;br /&gt;
| Value too large&lt;br /&gt;
|-&lt;br /&gt;
| -90&lt;br /&gt;
| 0xFFFFA6&lt;br /&gt;
| ENOSTR&lt;br /&gt;
| Not a stream&lt;br /&gt;
|-&lt;br /&gt;
| -91&lt;br /&gt;
| 0xFFFFA5&lt;br /&gt;
| ENODATA&lt;br /&gt;
| No data available&lt;br /&gt;
|-&lt;br /&gt;
| -94&lt;br /&gt;
| 0xFFFFA2&lt;br /&gt;
| ENOSR&lt;br /&gt;
| Out of streams resources&lt;br /&gt;
|-&lt;br /&gt;
| -97&lt;br /&gt;
| 0xFFFFFF9F&lt;br /&gt;
| EPROTO&lt;br /&gt;
| Protocol error&lt;br /&gt;
|-&lt;br /&gt;
| -111&lt;br /&gt;
| 0xFFFFFF91&lt;br /&gt;
| ETIMEDOUT&lt;br /&gt;
| Connection timed out&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== GSP-Specific Error Codes (Observed in Firmware) ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Errors ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Hex&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x1E&lt;br /&gt;
| 0x0000001E&lt;br /&gt;
| ETIME&lt;br /&gt;
| WPR/RPC timeout&lt;br /&gt;
|-&lt;br /&gt;
| 0x1F&lt;br /&gt;
| 0x0000001F&lt;br /&gt;
| EDEV&lt;br /&gt;
| Device error&lt;br /&gt;
|-&lt;br /&gt;
| 0x25&lt;br /&gt;
| 0x00000025&lt;br /&gt;
| EOVERFLOW&lt;br /&gt;
| Region/offset overflow&lt;br /&gt;
|-&lt;br /&gt;
| 0x37&lt;br /&gt;
| 0x00000037&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Invalid alignment/size&lt;br /&gt;
|-&lt;br /&gt;
| 0x51&lt;br /&gt;
| 0x00000051&lt;br /&gt;
| ENOMEM&lt;br /&gt;
| Allocator exhausted&lt;br /&gt;
|-&lt;br /&gt;
| 0x56&lt;br /&gt;
| 0x00000056&lt;br /&gt;
| EBUSY&lt;br /&gt;
| Resource busy&lt;br /&gt;
|-&lt;br /&gt;
| 0xFFFF&lt;br /&gt;
| 0xFFFFFFFF&lt;br /&gt;
| EPERM&lt;br /&gt;
| Permission denied&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== RPC Errors ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Hex&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x1D&lt;br /&gt;
| 0x0000001D&lt;br /&gt;
| EFAULT&lt;br /&gt;
| Bad address in RPC&lt;br /&gt;
|-&lt;br /&gt;
| 0x1E&lt;br /&gt;
| 0x0000001E&lt;br /&gt;
| ETIMEDOUT&lt;br /&gt;
| RPC timeout&lt;br /&gt;
|-&lt;br /&gt;
| 0x1F&lt;br /&gt;
| 0x0000001F&lt;br /&gt;
| EPROTO&lt;br /&gt;
| Protocol violation&lt;br /&gt;
|-&lt;br /&gt;
| 0x20&lt;br /&gt;
| 0x00000020&lt;br /&gt;
| EBADRPC&lt;br /&gt;
| Invalid RPC type&lt;br /&gt;
|-&lt;br /&gt;
| 0x21&lt;br /&gt;
| 0x00000021&lt;br /&gt;
| EBADSEQ&lt;br /&gt;
| Sequence mismatch&lt;br /&gt;
|-&lt;br /&gt;
| 0x22&lt;br /&gt;
| 0x00000022&lt;br /&gt;
| EBADSIZE&lt;br /&gt;
| Payload size error&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== BAR Errors ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Hex&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x30&lt;br /&gt;
| 0x00000030&lt;br /&gt;
| EBARINVAL&lt;br /&gt;
| Invalid BAR index&lt;br /&gt;
|-&lt;br /&gt;
| 0x31&lt;br /&gt;
| 0x00000031&lt;br /&gt;
| EBARPERM&lt;br /&gt;
| BAR access denied&lt;br /&gt;
|-&lt;br /&gt;
| 0x32&lt;br /&gt;
| 0x00000032&lt;br /&gt;
| EBARSIZE&lt;br /&gt;
| Aperture size error&lt;br /&gt;
|-&lt;br /&gt;
| 0x33&lt;br /&gt;
| 0x00000033&lt;br /&gt;
| EBARALIGN&lt;br /&gt;
| Alignment error&lt;br /&gt;
|-&lt;br /&gt;
| 0x34&lt;br /&gt;
| 0x00000034&lt;br /&gt;
| EBARRANGE&lt;br /&gt;
| Offset out of range&lt;br /&gt;
|-&lt;br /&gt;
| 0x35&lt;br /&gt;
| 0x00000035&lt;br /&gt;
| EBARBUSY&lt;br /&gt;
| BAR busy&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== WPR Errors ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Hex&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x40&lt;br /&gt;
| 0x00000040&lt;br /&gt;
| EWPRINVAL&lt;br /&gt;
| Invalid WPR region&lt;br /&gt;
|-&lt;br /&gt;
| 0x41&lt;br /&gt;
| 0x00000041&lt;br /&gt;
| EWPRPERM&lt;br /&gt;
| WPR permission denied&lt;br /&gt;
|-&lt;br /&gt;
| 0x42&lt;br /&gt;
| 0x00000042&lt;br /&gt;
| EWPROVERLAP&lt;br /&gt;
| Overlapping WPR regions&lt;br /&gt;
|-&lt;br /&gt;
| 0x43&lt;br /&gt;
| 0x00000043&lt;br /&gt;
| EWPRBUSY&lt;br /&gt;
| WPR operation in progress&lt;br /&gt;
|-&lt;br /&gt;
| 0x44&lt;br /&gt;
| 0x00000044&lt;br /&gt;
| EWPRTIMEOUT&lt;br /&gt;
| WPR timeout&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Migration Errors ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Hex&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x50&lt;br /&gt;
| 0x00000050&lt;br /&gt;
| EMIGINVAL&lt;br /&gt;
| Invalid migration phase&lt;br /&gt;
|-&lt;br /&gt;
| 0x51&lt;br /&gt;
| 0x00000051&lt;br /&gt;
| EMIGNOMEM&lt;br /&gt;
| Migration buffer OOM&lt;br /&gt;
|-&lt;br /&gt;
| 0x52&lt;br /&gt;
| 0x00000052&lt;br /&gt;
| EMIGBUSY&lt;br /&gt;
| Migration in progress&lt;br /&gt;
|-&lt;br /&gt;
| 0x53&lt;br /&gt;
| 0x00000053&lt;br /&gt;
| EMIGPHASE&lt;br /&gt;
| Phase mismatch&lt;br /&gt;
|-&lt;br /&gt;
| 0x54&lt;br /&gt;
| 0x00000054&lt;br /&gt;
| EMIGVERIFY&lt;br /&gt;
| Verification failed&lt;br /&gt;
|-&lt;br /&gt;
| 0x55&lt;br /&gt;
| 0x00000055&lt;br /&gt;
| EMIGCOMMIT&lt;br /&gt;
| Commit failed&lt;br /&gt;
|-&lt;br /&gt;
| 0x56&lt;br /&gt;
| 0x00000056&lt;br /&gt;
| EMIGABORT&lt;br /&gt;
| Migration aborted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Scheduler Errors ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Hex&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x60&lt;br /&gt;
| 0x00000060&lt;br /&gt;
| ESCHINVAL&lt;br /&gt;
| Invalid schedule params&lt;br /&gt;
|-&lt;br /&gt;
| 0x61&lt;br /&gt;
| 0x00000061&lt;br /&gt;
| ESCHPRIO&lt;br /&gt;
| Priority error&lt;br /&gt;
|-&lt;br /&gt;
| 0x62&lt;br /&gt;
| 0x00000062&lt;br /&gt;
| ESCHYIELD&lt;br /&gt;
| Yield failed&lt;br /&gt;
|-&lt;br /&gt;
| 0x63&lt;br /&gt;
| 0x00000063&lt;br /&gt;
| ESCHPREEMPT&lt;br /&gt;
| Preemption error&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Notification Errors ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Hex&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x70&lt;br /&gt;
| 0x00000070&lt;br /&gt;
| ENOTIFYINVAL&lt;br /&gt;
| Invalid notification&lt;br /&gt;
|-&lt;br /&gt;
| 0x71&lt;br /&gt;
| 0x00000071&lt;br /&gt;
| ENOTIFYBUSY&lt;br /&gt;
| Notification queue full&lt;br /&gt;
|-&lt;br /&gt;
| 0x72&lt;br /&gt;
| 0x00000072&lt;br /&gt;
| ENOTIFYDROP&lt;br /&gt;
| Notification dropped&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Error Code Mapping (Kernel Driver) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;static int gsp_errno_to_errno(int gsp_err) {&lt;br /&gt;
    switch (gsp_err) {&lt;br /&gt;
    case 0: return 0;&lt;br /&gt;
    case -1: return -EPERM;&lt;br /&gt;
    case -2: return -ENOENT;&lt;br /&gt;
    case -3: return -EINVAL;&lt;br /&gt;
    case -6: return -ENODEV;&lt;br /&gt;
    case -12: return -ENOMEM;&lt;br /&gt;
    case -16: return -EBUSY;&lt;br /&gt;
    case -22: return -EINVAL;&lt;br /&gt;
    case -28: return -ENOSPC;&lt;br /&gt;
    case -37: return -ENOLCK;&lt;br /&gt;
    case -56: return -EBADMSG;&lt;br /&gt;
    case -84: return -EOVERFLOW;&lt;br /&gt;
    case -90: return -ENOSTR;&lt;br /&gt;
    case -91: return -ENODATA;&lt;br /&gt;
    case -94: return -ENOSR;&lt;br /&gt;
    case -97: return -EPROTO;&lt;br /&gt;
    case -111: return -ETIMEDOUT;&lt;br /&gt;
    &lt;br /&gt;
    // GSP-specific&lt;br /&gt;
    case 0x1E: return -ETIMEDOUT;&lt;br /&gt;
    case 0x1F: return -EIO;&lt;br /&gt;
    case 0x25: return -EOVERFLOW;&lt;br /&gt;
    case 0x37: return -EINVAL;&lt;br /&gt;
    case 0x51: return -ENOMEM;&lt;br /&gt;
    case 0x56: return -EBUSY;&lt;br /&gt;
    case 0xFFFF: return -EPERM;&lt;br /&gt;
    &lt;br /&gt;
    // BAR&lt;br /&gt;
    case 0x30: return -EINVAL;&lt;br /&gt;
    case 0x31: return -EPERM;&lt;br /&gt;
    case 0x32: return -EINVAL;&lt;br /&gt;
    case 0x33: return -EINVAL;&lt;br /&gt;
    case 0x34: return -ERANGE;&lt;br /&gt;
    case 0x35: return -EBUSY;&lt;br /&gt;
    &lt;br /&gt;
    // WPR&lt;br /&gt;
    case 0x40: return -EINVAL;&lt;br /&gt;
    case 0x41: return -EPERM;&lt;br /&gt;
    case 0x42: return -EEXIST;&lt;br /&gt;
    case 0x43: return -EBUSY;&lt;br /&gt;
    case 0x44: return -ETIMEDOUT;&lt;br /&gt;
    &lt;br /&gt;
    // Migration&lt;br /&gt;
    case 0x50: return -EINVAL;&lt;br /&gt;
    case 0x51: return -ENOMEM;&lt;br /&gt;
    case 0x52: return -EBUSY;&lt;br /&gt;
    case 0x53: return -EINVAL;&lt;br /&gt;
    case 0x54: return -EIO;&lt;br /&gt;
    case 0x55: return -EIO;&lt;br /&gt;
    case 0x56: return -ECANCELED;&lt;br /&gt;
    &lt;br /&gt;
    // Scheduler&lt;br /&gt;
    case 0x60: return -EINVAL;&lt;br /&gt;
    case 0x61: return -EINVAL;&lt;br /&gt;
    case 0x62: return -EAGAIN;&lt;br /&gt;
    case 0x63: return -EAGAIN;&lt;br /&gt;
    &lt;br /&gt;
    // Notification&lt;br /&gt;
    case 0x70: return -EINVAL;&lt;br /&gt;
    case 0x71: return -EAGAIN;&lt;br /&gt;
    case 0x72: return -ENOBUFS;&lt;br /&gt;
    &lt;br /&gt;
    default: return -EIO;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging Error Codes ==&lt;br /&gt;
&lt;br /&gt;
=== GSP Log Format ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GSP_ERROR: rpc_type=0x0A seq=0x1234 err=0x31 (EBARPERM) vf=2 addr=0x7F000000&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Common Error Scenarios ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Scenario&lt;br /&gt;
! Error Code&lt;br /&gt;
! Resolution&lt;br /&gt;
|-&lt;br /&gt;
| VF writes to unmapped BAR&lt;br /&gt;
| 0x31 (EBARPERM)&lt;br /&gt;
| Check VF BAR config&lt;br /&gt;
|-&lt;br /&gt;
| Migration verify fails&lt;br /&gt;
| 0x54 (EMIGVERIFY)&lt;br /&gt;
| Check memory integrity&lt;br /&gt;
|-&lt;br /&gt;
| WPR timeout on page fault&lt;br /&gt;
| 0x44 (EWPRTIMEOUT)&lt;br /&gt;
| Increase timeout&lt;br /&gt;
|-&lt;br /&gt;
| RPC sequence mismatch&lt;br /&gt;
| 0x21 (EBADSEQ)&lt;br /&gt;
| Reset RPC client&lt;br /&gt;
|-&lt;br /&gt;
| Allocator exhausted&lt;br /&gt;
| 0x51 (ENOMEM)&lt;br /&gt;
| Free unused VF memory&lt;br /&gt;
|-&lt;br /&gt;
| BAR aperture too small&lt;br /&gt;
| 0x32 (EBARSIZE)&lt;br /&gt;
| Increase aperture&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Error Injection (Testing) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Inject errors for testing&lt;br /&gt;
#define GSP_INJECT_ERROR(rpc_type, err_code) \&lt;br /&gt;
    gsp_test_inject_error(gsp, rpc_type, err_code)&lt;br /&gt;
&lt;br /&gt;
void gsp_test_inject_error(struct gsp_device *gsp, &lt;br /&gt;
                           uint32_t rpc_type, int err_code) {&lt;br /&gt;
    struct inject_payload p = {&lt;br /&gt;
        .rpc_type = rpc_type,&lt;br /&gt;
        .error_code = err_code,&lt;br /&gt;
        .enable = 1,&lt;br /&gt;
    };&lt;br /&gt;
    gsp_rpc_send_sync(gsp-&amp;amp;gt;rpc, RPC_DEBUG, &amp;amp;amp;p, sizeof(p), NULL, NULL);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Guest_Driver_Lifecycle:_A_Field_Guide&amp;diff=23964</id>
		<title>Guest Driver Lifecycle: A Field Guide</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Guest_Driver_Lifecycle:_A_Field_Guide&amp;diff=23964"/>
		<updated>2026-10-12T04:40:06Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Guest Driver Lifecycle: A Field Guide =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' A walking tour of what happens between &amp;quot;guest boots&amp;quot; and &amp;quot;CUDA initializes&amp;quot;, using message, function and control IDs observed from an unmodified 570.144 guest. Canonical source: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/07-driver-lifecycle-field-guide.md &amp;lt;code&amp;gt;../docs/03-architecture/07-driver-lifecycle-field-guide.md&amp;lt;/code&amp;gt;]; if this page and the docs tree disagree, the docs tree wins.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed with the stock guest driver; &amp;lt;code&amp;gt;[design]&amp;lt;/code&amp;gt; stages documented ahead of arrival.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. How to read this page ==&lt;br /&gt;
&lt;br /&gt;
Each stage lists what the '''guest''' does, what the '''device/firmware''' must answer, what host emulation does today, and the log signature to look for (host-side &amp;lt;code&amp;gt;dmesg&amp;lt;/code&amp;gt; with prefixes &amp;lt;code&amp;gt;vgsp:&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;vgsp-rm:&amp;lt;/code&amp;gt;; guest-side &amp;lt;code&amp;gt;dmesg&amp;lt;/code&amp;gt; in the VM). IDs are for 570.144 on the Turing (TU104) profile; other generations add IDs and change versioned values, but the ''stages'' are stable.&lt;br /&gt;
&lt;br /&gt;
== 2. Stage map ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;guest boots&lt;br /&gt;
  │&lt;br /&gt;
  ├─ 1. PCI probe &amp;amp;amp; config space ........ lspci is the reference&lt;br /&gt;
  ├─ 2. GSP boot handshake .............. WPR, FWSEC, booter, RISC-V core&lt;br /&gt;
  ├─ 3. Static configuration ............ GET_GSP_STATIC_INFO (65)&lt;br /&gt;
  ├─ 4. Message queues .................. SET_GUEST_SYSTEM_INFO (1) + init traffic&lt;br /&gt;
  ├─ 5. RM control battery .............. GSP_RM_CONTROL (76) × ~160&lt;br /&gt;
  ├─ 6. Object creation ................. GSP_RM_ALLOC (103) × ~60&lt;br /&gt;
  └─ 7. UVM registration/context ........ cuInit → channel manager → execution frontier&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. PCI probe and config space ==&lt;br /&gt;
&lt;br /&gt;
'''Guest:''' reads IDs, walks capabilities, sizes BARs, enables Memory Space and Bus Master, programs MSI-X. '''Device must:''' report a coherent TU104-family GPU with 16 MB BAR0, 256 MB BAR1, an MSI-X capability and a link capability the driver accepts. '''Emulation:''' config space is synthesized and BAR sizes are enforced. The hypervisor is the usual source of surprises — a device on the root bus can have its PCIe capability rewritten to &amp;quot;root complex integrated endpoint&amp;quot;, removing link information the driver wants; attach behind a root port. '''Log:''' guest-side &amp;lt;code&amp;gt;lspci -vvv&amp;lt;/code&amp;gt; is the reference.&lt;br /&gt;
&lt;br /&gt;
== 4. GSP boot handshake ==&lt;br /&gt;
&lt;br /&gt;
'''Guest:''' writes WPR descriptors, releases FWSEC, then the booter, then the RISC-V core; polls a status mailbox for &amp;quot;GSP init done&amp;quot;. '''Device must:''' complete every stage in the order the driver polls and leave the mailbox in the state the driver expects. '''Emulation:''' the host module models the stage state machine and auto-clears self-clearing triggers (e.g. MMU invalidate registers) so polls terminate.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;vgsp: GSP-BOOT: ... trigger auto-cleared ...&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. Static configuration ==&lt;br /&gt;
&lt;br /&gt;
'''Guest:''' &amp;lt;code&amp;gt;GET_GSP_STATIC_INFO&amp;lt;/code&amp;gt; (65) → a large &amp;lt;code&amp;gt;GspStaticConfigInfo&amp;lt;/code&amp;gt; structure; reads the VBIOS image from the BAR0 window; queries device/FB/BUS info. '''Device must:''' provide self-consistent sizes, engine inventories, memory geometry, interrupt topology and a parseable VBIOS blob. '''Emulation:''' the static structures are synthesized for TU104 (FB size, BAR layout, engine list, vGPU-friendly VF values).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;vgsp-rm: GET_GSP_STATIC_INFO → ...&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Message queues ==&lt;br /&gt;
&lt;br /&gt;
'''Guest:''' sends &amp;lt;code&amp;gt;SET_GUEST_SYSTEM_INFO&amp;lt;/code&amp;gt; (1) with libos regions, a queue buffer description and a page table (the buffer is &amp;lt;code&amp;gt;NV_MEMORY_NONCONTIGUOUS&amp;lt;/code&amp;gt;); also &amp;lt;code&amp;gt;GSP_SET_SYSTEM_INFO&amp;lt;/code&amp;gt; (72), &amp;lt;code&amp;gt;SET_REGISTRY&amp;lt;/code&amp;gt; (73) and &amp;lt;code&amp;gt;CONTINUATION_RECORD&amp;lt;/code&amp;gt; (71) as init traffic. '''Device must:''' consume them silently (async) and consume the command queue exactly in the guest's write order. '''Emulation:''' parses the queue chain, builds the geometry, links the status queue and consumes elements one by one — '''element-based, not byte-stream-based''': one message is one element and may span pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;vgsp: libos region[i] id8=... pa=... size=...&lt;br /&gt;
vgsp: queue args sharedPA=... ptes=... cmdOff=... statOff=...&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7. The RM control battery ==&lt;br /&gt;
&lt;br /&gt;
'''Guest:''' sends &amp;lt;code&amp;gt;GSP_RM_CONTROL&amp;lt;/code&amp;gt; (76) for every subsystem it initializes. Of the ~160 observed control IDs, 23 are special-cased with real values; the rest are answered with a generic &amp;lt;code&amp;gt;SUCCESS&amp;lt;/code&amp;gt; and zeroed params (the fallback).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Control&lt;br /&gt;
! Meaning&lt;br /&gt;
! What matters&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20800a40&amp;lt;/code&amp;gt; family&lt;br /&gt;
| internal device info table&lt;br /&gt;
| per-index values, entry count&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20801112&amp;lt;/code&amp;gt;&lt;br /&gt;
| FIFO device info table&lt;br /&gt;
| engine inventory; count must match engine queries&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20800a5c&amp;lt;/code&amp;gt;&lt;br /&gt;
| interrupt kernel table&lt;br /&gt;
| vector topology the driver maps&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20800a59&amp;lt;/code&amp;gt;&lt;br /&gt;
| GMMU static info&lt;br /&gt;
| fault buffer sizes; a wrong value breaks UVM early&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20800a01&amp;lt;/code&amp;gt;&lt;br /&gt;
| display static info&lt;br /&gt;
| display count; headless values are fine&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20801823/-a/-b&amp;lt;/code&amp;gt;&lt;br /&gt;
| BUS/FB info V2&lt;br /&gt;
| sysmem connection type and PCIe link caps feed bandwidth math&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20802a07&amp;lt;/code&amp;gt;&lt;br /&gt;
| CE physical caps&lt;br /&gt;
| per-engine bits; UVM refuses channels without &amp;lt;code&amp;gt;sysmem&amp;lt;/code&amp;gt; support&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20802a0a/0b&amp;lt;/code&amp;gt;&lt;br /&gt;
| all-CE caps&lt;br /&gt;
| caps table for all engines&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20802a02&amp;lt;/code&amp;gt;&lt;br /&gt;
| CE PCE mask&lt;br /&gt;
| one bit per engine&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20802a08&amp;lt;/code&amp;gt;&lt;br /&gt;
| CE fault method buffer size&lt;br /&gt;
| method buffer sizing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x90f10106&amp;lt;/code&amp;gt;&lt;br /&gt;
| vaspace reserved-PDE contract&lt;br /&gt;
| carries page-table physical addresses (see [[GSP RPC Emulation|&amp;lt;code&amp;gt;GSP-RPC-Emulation.md&amp;lt;/code&amp;gt;]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20800123&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;0x20800170&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;GPU_GET_ENGINES&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;GET_ENGINES_V2&amp;lt;/code&amp;gt;&lt;br /&gt;
| engine inventory; the guest must see the full list, including async copy (&amp;lt;code&amp;gt;COPY14&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x800201&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;GPU_GET_CLASSLIST&amp;lt;/code&amp;gt;&lt;br /&gt;
| class list; must agree with engine list and CE caps&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x2080012b&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;GPU_PROMOTE_CTX&amp;lt;/code&amp;gt; (560-byte params)&lt;br /&gt;
| load-bearing GR context-validity operation; a wrong shape is a server wedge handled by the supervised fail-safe&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20803039&amp;lt;/code&amp;gt;&lt;br /&gt;
| NVLink masks/VBIOS info&lt;br /&gt;
| fallback: generic &amp;lt;code&amp;gt;SUCCESS&amp;lt;/code&amp;gt; with zeroed params&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x20800a70&amp;lt;/code&amp;gt;&lt;br /&gt;
| BUS flush with sysmembar&lt;br /&gt;
| fallback: generic &amp;lt;code&amp;gt;SUCCESS&amp;lt;/code&amp;gt; with zeroed params; UVM issues these often&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;vgsp-rm: GSP_RM_CONTROL cmd=0x... hClient=0x... hObject=0x... paramsSize=...&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Object creation ==&lt;br /&gt;
&lt;br /&gt;
'''Guest:''' &amp;lt;code&amp;gt;GSP_RM_ALLOC&amp;lt;/code&amp;gt; (103) creates the object tree. Typical order for a CUDA process:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;0x0        NV01_ROOT              (client root, 120-byte params)&lt;br /&gt;
0x80       NV01_DEVICE_0          (56 bytes)&lt;br /&gt;
0x2080     NV20_SUBDEVICE_0       (4 bytes)&lt;br /&gt;
0x90f1     FERMI_VASPACE_A        (48 bytes)  ← the GPU address space&lt;br /&gt;
0xa06c     KEPLER_CHANNEL_GROUP_A (20 bytes)  ← CE channel group&lt;br /&gt;
0xc46f     TURING_CHANNEL_GPFIFO_A(368 bytes) ← the channel (GPFIFO VA, instance/userd descriptors)&lt;br /&gt;
0xc076     GP100_UVM_SW           (0 bytes)&lt;br /&gt;
0xc5b5     TURING_DMA_COPY_A      (8 bytes)   ← CE object&lt;br /&gt;
0xc5c0     TURING_COMPUTE_A       (16 bytes)  ← compute object (engine registration path)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A hard-won rule from the &amp;lt;code&amp;gt;TURING_COMPUTE_A&amp;lt;/code&amp;gt; (0xc5c0) alloc: the caller may issue it with &amp;lt;code&amp;gt;paramsSize=0&amp;lt;/code&amp;gt; against a small stack local while the kernel side treats the class params as 16 bytes and copies reply params back. The emulation must '''echo the request params back in the alloc reply''', or the user-mode client segfaults. Channel parameters decode into &amp;lt;code&amp;gt;gpFifoOffset&amp;lt;/code&amp;gt; (a GPU VA), &amp;lt;code&amp;gt;gpFifoEntries&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;engineType&amp;lt;/code&amp;gt; (e.g. &amp;lt;code&amp;gt;COPY0 = 0x9&amp;lt;/code&amp;gt;), and &amp;lt;code&amp;gt;NV_MEMORY_DESC_PARAMS&amp;lt;/code&amp;gt; for instance/userd/ramfc/method buffers with '''physical''' addresses and apertures (&amp;lt;code&amp;gt;ADDR_SYSMEM = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ADDR_FBMEM = 2&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;vgsp-rm: GSP_RM_ALLOC class=0x... paramsSize=... hClient=... hParent=... hObject=...&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 9. UVM registration and the execution frontier ==&lt;br /&gt;
&lt;br /&gt;
'''Guest:''' &amp;lt;code&amp;gt;cuInit&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;UVM_REGISTER_GPU&amp;lt;/code&amp;gt; → channel-manager creation → page-tree initialization; each UVM channel does a first push and waits on a semaphore. '''Emulation today:''' the host decodes the pushes UVM generates and executes their memsets, copies and semaphore releases in software by translating the semaphore VA to a guest physical address — a bridge, not forwarding: no work reaches the physical GPU through it yet.&lt;br /&gt;
&lt;br /&gt;
'''Progress:''' context creation now returns (the driver-API smoke completes end to end) and the frontier is execution. The host GR ladder allocates a GR0 channel and a compute-class object; a first semaphore push against an uncommitted GR context faulted &amp;lt;code&amp;gt;CTXNOTVALID&amp;lt;/code&amp;gt;, and a following &amp;lt;code&amp;gt;GPU_PROMOTE_CTX&amp;lt;/code&amp;gt; wedged GSP-RM into its designed locked fail-safe. Later, a forwarded guest CUDA launch reached the front-end (ring entry fetched, methods executed) with no observed inline launch-descriptor install and no grid dispatched; context validity at dispatch is ruled out. See [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]. The roadmap from here is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;UVM registers → cuInit returns → context creation → memory allocation&lt;br /&gt;
→ channel creation for the process → kernel launch → (real execution)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each remaining step needs the same treatment: satisfy the interface, forward the work, relay the completions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;nvidia-uvm: ... Tracker entry for value N (sema VA 0x...) channel ID ... CE ...&lt;br /&gt;
nvidia-uvm: ... pending push '' started at ... in channel_init() releasing value N&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 10. Quick reference: function IDs from a stock 570.144 guest ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Function&lt;br /&gt;
! Name&lt;br /&gt;
! Frequency per CUDA run (approx.)&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| SET_GUEST_SYSTEM_INFO&lt;br /&gt;
| once&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| FREE&lt;br /&gt;
| ~14&lt;br /&gt;
|-&lt;br /&gt;
| 47&lt;br /&gt;
| UNLOADING_GUEST_DRIVER&lt;br /&gt;
| on unload&lt;br /&gt;
|-&lt;br /&gt;
| 65&lt;br /&gt;
| GET_GSP_STATIC_INFO&lt;br /&gt;
| once&lt;br /&gt;
|-&lt;br /&gt;
| 70&lt;br /&gt;
| UPDATE_BAR_PDE&lt;br /&gt;
| a few&lt;br /&gt;
|-&lt;br /&gt;
| 71/72/73&lt;br /&gt;
| CONTINUATION_RECORD / GSP_SET_SYSTEM_INFO / SET_REGISTRY&lt;br /&gt;
| once each&lt;br /&gt;
|-&lt;br /&gt;
| 76&lt;br /&gt;
| GSP_RM_CONTROL&lt;br /&gt;
| ~160&lt;br /&gt;
|-&lt;br /&gt;
| 103&lt;br /&gt;
| GSP_RM_ALLOC&lt;br /&gt;
| ~60&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If a new driver version produces '''new function numbers''', do not guess: add a handler that logs the raw payload, then decode it against that version's observed traffic.&lt;br /&gt;
&lt;br /&gt;
== 11. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/07-driver-lifecycle-field-guide.md &amp;lt;code&amp;gt;../docs/03-architecture/07-driver-lifecycle-field-guide.md&amp;lt;/code&amp;gt;] — canonical field guide.&lt;br /&gt;
* [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]] — GSP boot, message queues and RM architecture.&lt;br /&gt;
* [[GSP RPC Emulation|&amp;lt;code&amp;gt;GSP-RPC-Emulation.md&amp;lt;/code&amp;gt;]] — control/alloc emulation on the host side.&lt;br /&gt;
* [[RPC Message Format|&amp;lt;code&amp;gt;RPC-Message-Format.md&amp;lt;/code&amp;gt;]] — wire format of the function 76/103 traffic.&lt;br /&gt;
* [[Address Reference|&amp;lt;code&amp;gt;Address-Reference.md&amp;lt;/code&amp;gt;]] and [[GSP 570.144W Firmware Analysis|&amp;lt;code&amp;gt;GSP-570.144W-Firmware-Analysis.md&amp;lt;/code&amp;gt;]] — ID reference and the firmware they belong to.&lt;br /&gt;
* [[UVM in the Guest|&amp;lt;code&amp;gt;UVM-in-the-Guest.md&amp;lt;/code&amp;gt;]], [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]], [[The Host Module (vgsp.ko)|&amp;lt;code&amp;gt;Host-Module.md&amp;lt;/code&amp;gt;]], [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]] — registration, the frontier, the host stages and the forwarding backend.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=CUDA_Userspace_Driver&amp;diff=23963</id>
		<title>CUDA Userspace Driver</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=CUDA_Userspace_Driver&amp;diff=23963"/>
		<updated>2026-10-12T04:40:06Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= CUDA Userspace Driver (&amp;lt;code&amp;gt;libcuda.so&amp;lt;/code&amp;gt;) — Analysis Deep Dive =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Status (2026-10-12, honest).''' The analysis covers the whole library for driver 570.144 and the tooling is version-agnostic. The ''control plane'' gets the stock guest stack through &amp;lt;code&amp;gt;cuInit&amp;lt;/code&amp;gt;, device enumeration, &amp;lt;code&amp;gt;cuCtxCreate&amp;lt;/code&amp;gt; and the full driver-API smoke test — allocation, copies, free and destroy complete end to end (&amp;lt;code&amp;gt;ALL OK&amp;lt;/code&amp;gt;; the 64-byte payload round-trips exactly). The ''data plane'' decodes guest push buffers and executes the memory and semaphore work it understands; CUDA kernel launches are forwarded to the physical execution path, where a launch reaches the engine queue (front-end deposit and scheduling are observed) but an engine-authored release is not yet observed. Green runs are not yet reproducible on every boot — an open issue, tracked in the repository. Canonical detail: [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/docs/01-architecture.md &amp;lt;code&amp;gt;01-architecture.md&amp;lt;/code&amp;gt;] through &amp;lt;code&amp;gt;08&amp;lt;/code&amp;gt;; reading order [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/READ-ME-FIRST.md &amp;lt;code&amp;gt;../userspace/cuda/READ-ME-FIRST.md&amp;lt;/code&amp;gt;]; front door [https://git.vgpu.io/open-iov.git/tree/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. What it is ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;libcuda.so.1.1&amp;lt;/code&amp;gt; is the userspace half of the CUDA driver: the library an application or language runtime loads to talk to a GPU. For 570.144 it is a '''single, fully stripped, position-independent shared object of about 71 MB''':&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property&lt;br /&gt;
! Value&lt;br /&gt;
|-&lt;br /&gt;
| Exports&lt;br /&gt;
| 659 (public &amp;lt;code&amp;gt;cu*&amp;lt;/code&amp;gt; API plus internal/legacy entry points)&lt;br /&gt;
|-&lt;br /&gt;
| Imports&lt;br /&gt;
| 243 — libc/libpthread/libdl/librt only; no NVIDIA userspace dependency on the CUDA path&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.text&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;0x179ec0&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;0xe94c63&amp;lt;/code&amp;gt; (13.7 MB); 29,494 functions found by full analysis (28,925 with unwind tables)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;.rodata&amp;lt;/code&amp;gt;&lt;br /&gt;
| ~53 MB — error strings, dispatch/version tables, '''embedded device code'''&lt;br /&gt;
|-&lt;br /&gt;
| CUDA note&lt;br /&gt;
| CUDA 12.8; supported kernel-driver ABIs &amp;lt;code&amp;gt;[470, 535, 550, 560, 565, 570]&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Two entry surfaces coexist: the '''public driver API''' (&amp;lt;code&amp;gt;cuInit&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cuCtxCreate_v2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cuMemAlloc_v2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cuLaunchKernel&amp;lt;/code&amp;gt;, …) and the '''entry-table API''' — &amp;lt;code&amp;gt;cuGetExportTable&amp;lt;/code&amp;gt;, a 128-bit-UUID-keyed lookup that hands internal tables to the CUDA runtime (&amp;lt;code&amp;gt;libcudart&amp;lt;/code&amp;gt;), tooling and interposition libraries. Tables are versioned by a leading &amp;lt;code&amp;gt;struct_size&amp;lt;/code&amp;gt; field and are append-only.&lt;br /&gt;
&lt;br /&gt;
The library embeds '''device code''' — cubins for memcpy/memset kernels, the graph scheduler, syscall trampolines and preemption-handler assembly — and loads it through its own module machinery, so a stripped &amp;lt;code&amp;gt;libcuda.so&amp;lt;/code&amp;gt; still contains many small ELF images in &amp;lt;code&amp;gt;.rodata&amp;lt;/code&amp;gt;. The CUDA ''runtime'' (&amp;lt;code&amp;gt;libcudart&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;cuda*&amp;lt;/code&amp;gt; API) is a separate stock library that bottoms out in &amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt;; it also calls through the entry tables, so a guest failure in a &amp;lt;code&amp;gt;cuda*&amp;lt;/code&amp;gt; call may reach driver code through a different door than the public &amp;lt;code&amp;gt;cu*&amp;lt;/code&amp;gt; entry point.&lt;br /&gt;
&lt;br /&gt;
'''Open-IOV requires this library unmodified.''' In the guest it links against the guest's stock &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;nvidia-uvm.ko&amp;lt;/code&amp;gt; exactly as on bare metal; there is no &amp;lt;code&amp;gt;LD_PRELOAD&amp;lt;/code&amp;gt; shim and no patch. Instrumentation uses &amp;lt;code&amp;gt;ptrace&amp;lt;/code&amp;gt; or kernel-side tracing, because the RM client issues raw &amp;lt;code&amp;gt;syscall(SYS_ioctl)&amp;lt;/code&amp;gt; rather than libc &amp;lt;code&amp;gt;ioctl&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 2. Layer model ==&lt;br /&gt;
&lt;br /&gt;
The library is strictly layered, and the boundaries are where the emulation interfaces live (condensed from &amp;lt;code&amp;gt;docs/01&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;docs/02&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;application / libcudart&lt;br /&gt;
      | public cu* API or UUID entry tables&lt;br /&gt;
      v&lt;br /&gt;
generated wrappers -&amp;amp;gt; API layer -&amp;amp;gt; CUDA internal engine&lt;br /&gt;
                                      |-- driver-model layer (RM) -&amp;amp;gt; /dev/nvidia* ioctls&lt;br /&gt;
                                      |-- hardware layer (QMD/method encoding)&lt;br /&gt;
                                      |     -&amp;amp;gt; GPU queues, doorbells&lt;br /&gt;
                                      |-- UVM userspace (managed memory) -&amp;amp;gt; /dev/nvidia-uvm&lt;br /&gt;
                                      '-- JIT/ELF (PTX-&amp;amp;gt;SASS, cubin loading)&lt;br /&gt;
kernel driver + GSP-RM + GPU&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Generated wrappers and API layer.''' A master export list (name, platform flags, CUDA version introduced) generates the exported symbols, wrappers, tool callbacks and &amp;lt;code&amp;gt;cuGetProcAddress&amp;lt;/code&amp;gt; tables (&amp;lt;code&amp;gt;_vN&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;_ptsz&amp;lt;/code&amp;gt; variants are part of that data). Below it, the hand-written layer reads the per-thread context stack, validates state, takes one context lock, calls one engine function and returns a &amp;lt;code&amp;gt;CUresult&amp;lt;/code&amp;gt; — the semantic work is always one layer down.&lt;br /&gt;
* '''Internal engine.''' Owns the object graph: process globals (init state, kernel-client handle, device list), device (chip/caps/limits, vtables), context (memory/channel/stream managers, QMD pools, ISR thread), stream, module/function, memory objects, events/graphs/libraries.&lt;br /&gt;
* '''Driver-model layer.''' Selected at initialization behind one function table: the '''RM backend''' (the one Open-IOV cares about) plus SoC, Amodel, MPS and WDDM. It turns engine operations into RM controls and object allocations over &amp;lt;code&amp;gt;/dev/nvidia*&amp;lt;/code&amp;gt;, and owns the '''driver-ABI adaptation''' layer — one instance per supported kernel-driver ABI, chosen at &amp;lt;code&amp;gt;cuInit&amp;lt;/code&amp;gt;.&lt;br /&gt;
* '''Hardware layer.''' Chip-specific method/QMD/semaphore/doorbell encoders selected by compute capability. The userspace driver ''builds'' the GPU command streams; the kernel driver allocates, maps, schedules and services interrupts.&lt;br /&gt;
* '''Synchronization model.''' Three primitives explain most of it: the '''tracking semaphore''' (per-channel counter of completed pushes), the '''marker''' (&amp;quot;all work before this point&amp;quot;) and the '''QMD semaphore''' (released when a grid completes). Blocking waits use a per-context ISR thread and a DPC queue.&lt;br /&gt;
&lt;br /&gt;
== 3. What it touches in a guest ==&lt;br /&gt;
&lt;br /&gt;
This is the emulation contract; the full checklist is &amp;lt;code&amp;gt;docs/03&amp;lt;/code&amp;gt; §9.&lt;br /&gt;
&lt;br /&gt;
'''Device nodes.''' &amp;lt;code&amp;gt;/dev/nvidiactl&amp;lt;/code&amp;gt; (process-wide control: version negotiation, client creation, GPU attach, OS events, exported-object fds), &amp;lt;code&amp;gt;/dev/nvidiaN&amp;lt;/code&amp;gt; (per-GPU: object alloc/free, RM controls, memory alloc/map, event allocation), &amp;lt;code&amp;gt;/dev/nvidia-uvm&amp;lt;/code&amp;gt; (managed memory and page migration) and &amp;lt;code&amp;gt;/dev/nvidia-vgpuN&amp;lt;/code&amp;gt; (vGPU plugin node; NVIDIA's own vGPU stack only, not used by stock CUDA paths).&lt;br /&gt;
&lt;br /&gt;
'''ioctls.''' The control device uses &amp;lt;code&amp;gt;_IOWR('F', cmd, …)&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;200&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;NV_ESC_CARD_INFO&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;210&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;NV_ESC_CHECK_VERSION_STR&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;212&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;NV_ESC_ATTACH_GPUS_TO_FD&amp;lt;/code&amp;gt;. RM escapes include &amp;lt;code&amp;gt;0x2b&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;NV_ESC_RM_ALLOC&amp;lt;/code&amp;gt; ('''the main object-allocation path'''), &amp;lt;code&amp;gt;0x2a&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;NV_ESC_RM_CONTROL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x29&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;NV_ESC_RM_FREE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x4e&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;0x4f&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;NV_ESC_RM_MAP_MEMORY&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;UNMAP_MEMORY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x57&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;0x58&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;NV_ESC_RM_MAP_MEMORY_DMA&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;UNMAP_MEMORY_DMA&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;0x4a&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;NV_ESC_RM_VID_HEAP_CONTROL&amp;lt;/code&amp;gt;. The request word &amp;lt;code&amp;gt;rsi=0xc030462b&amp;lt;/code&amp;gt; in a crash dump decodes to &amp;quot;allocating an RM object with a 48-byte payload&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
'''RM objects/classes.''' Every RM call names a class. Observed for 570.144 on an emulated TU104: &amp;lt;code&amp;gt;NV01_ROOT&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x0&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;NV01_DEVICE_0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x80&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;NV20_SUBDEVICE_0&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x2080&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;NV01_EVENT&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x40&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;KEPLER_CHANNEL_GROUP_A&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0xa06c&amp;lt;/code&amp;gt;), a channel-group/runlist object (&amp;lt;code&amp;gt;0x9067&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;TURING_CHANNEL_GPFIFO_A&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0xc46f&amp;lt;/code&amp;gt;, the channel), &amp;lt;code&amp;gt;TURING_COMPUTE_A&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0xc5c0&amp;lt;/code&amp;gt;, the compute engine object), plus memory (&amp;lt;code&amp;gt;0x3e&amp;lt;/code&amp;gt;) and VA-space classes. The observed &amp;lt;code&amp;gt;cuCtxCreate&amp;lt;/code&amp;gt; order is root → device → subdevice → events → channel group → channel-group object → memory → channel → control &amp;lt;code&amp;gt;NV0080_CTRL_CMD_FIFO_GET_CHANNELLIST&amp;lt;/code&amp;gt; → compute object → engine registration.&lt;br /&gt;
&lt;br /&gt;
'''Controls.''' Device/GPU info (&amp;lt;code&amp;gt;GPU_GET_ENGINES&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GPU_GET_CLASSLIST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GPU_GET_VIRTUALIZATION_MODE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FB_GET_INFO&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CE_GET_CAPS&amp;lt;/code&amp;gt;, …), FIFO/channels (&amp;lt;code&amp;gt;NV0080_CTRL_CMD_FIFO_GET_CHANNELLIST&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;0x80170d&amp;lt;/code&amp;gt;, GPFIFO scheduling, timeslices, &amp;lt;code&amp;gt;GET_CLASS_ENGINEID&amp;lt;/code&amp;gt;), GR/context switches, memory, events and interrupts, vGPU/licensing queries, and perf/clocks. The driver tolerates unknown-but-successful controls; it only fails when a ''specific reply field'' is consumed and wrong.&lt;br /&gt;
&lt;br /&gt;
'''Memory.''' VA reservation (&amp;lt;code&amp;gt;NV_ESC_RM_VID_HEAP_CONTROL&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;NVOS32&amp;lt;/code&amp;gt;), backing allocation (vidmem/sysmem, pinned host memory, imported handles, UVM) and mapping (&amp;lt;code&amp;gt;NVOS33&amp;lt;/code&amp;gt; into the process, &amp;lt;code&amp;gt;NVOS46&amp;lt;/code&amp;gt; into a device VA space). All guest memory CUDA uses is either an RM allocation backed by emulated VRAM/BAR1 or pinned guest RAM the GPU must DMA to.&lt;br /&gt;
&lt;br /&gt;
'''Channels, GPFIFO, USERD, doorbells.''' A channel is a GPFIFO (array of pushbuffer descriptors) plus engine objects. The driver allocates the GPFIFO, error notifier and (Volta and later) the USERD itself, passing the handles to the channel allocation; submission writes the GPFIFO put pointer into USERD and rings a doorbell token returned by the channel allocation. Pushbuffers are method streams terminated by a tracking-semaphore release and a new GPFIFO entry; the host emulation decodes them as such.&lt;br /&gt;
&lt;br /&gt;
'''Synchronization below the API.''' Semaphores (plain GPU-visible memory values), 4 KB per-channel error notifiers, OS events (kernel objects used to wake blocked threads), interrupts routed through the kernel driver, and a trap handler for debuggers and &amp;lt;code&amp;gt;device-side assert&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''UVM and GSP-RM.''' When UVM is available the driver registers GPUs, VA spaces, channels and managed allocations and pushes UVM semaphores into the same streams; without it CUDA degrades to zero-copy. GSP-RM changes nothing from userspace — it still issues RM ioctls; inside the kernel driver controls become GSP-RM RPCs, which Open-IOV's host module answers.&lt;br /&gt;
&lt;br /&gt;
== 4. Why forwarding matters, and where we are ==&lt;br /&gt;
&lt;br /&gt;
The performance budget is dominated by '''push-buffer execution''', '''synchronization latency''' and (once, at setup) '''control-plane latency''' (&amp;lt;code&amp;gt;docs/04&amp;lt;/code&amp;gt; §4). Only forwarding ''real work'' to the physical GPU meets the first two; software execution of state/memory ops is a correctness bridge, not the data plane (&amp;lt;code&amp;gt;docs/08&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
* '''Stated architecture:''' ''emulate the interface, pass through the work, never patch anyone.'' Prototype the host-RM/GSP proxy first for correctness, measure, then move the hot path to direct submission if the budgets demand it — work path abstracted from day one.&lt;br /&gt;
* '''Control plane today:''' GSP-RM emulation, RPC handling, BAR/PCI/MSI-X emulation and object/control replies are implemented; the stock guest stack completes &amp;lt;code&amp;gt;cuInit&amp;lt;/code&amp;gt;, device enumeration, &amp;lt;code&amp;gt;cuCtxCreate&amp;lt;/code&amp;gt; and the driver-API smoke test (allocation, copies, free and destroy).&lt;br /&gt;
* '''Current frontier:''' a guest CUDA kernel launch is forwarded and reaches the physical engine queue — the front end deposits the launch and the scheduling path accepts it — but the engine does not yet execute the forwarded launch descriptor: an engine-authored release is the only proof of execution and it is not observed. The per-boot green/stall variance on the emulation path is an open issue, tracked in the repository. The chain, the evidence and the live state are on [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
* '''Data plane today:''' the host module decodes guest push buffers as method streams and executes the memory and semaphore work it understands (memsets, copies, semaphore releases), and forwards engine-class work to the physical backend; kernel launches are forwarded but not yet executed by the engine.&lt;br /&gt;
&lt;br /&gt;
== 5. The crash-path lesson: replies are consumed data ==&lt;br /&gt;
&lt;br /&gt;
The old deterministic &amp;lt;code&amp;gt;cuCtxCreate&amp;lt;/code&amp;gt; segfault at &amp;lt;code&amp;gt;libcuda+0x453f90&amp;lt;/code&amp;gt; shows why reply coherence matters (&amp;lt;code&amp;gt;docs/05&amp;lt;/code&amp;gt; §3.5, &amp;lt;code&amp;gt;docs/04&amp;lt;/code&amp;gt; §6). The engine-registration hook allocates a &amp;lt;code&amp;gt;TURING_COMPUTE_A&amp;lt;/code&amp;gt; object with &amp;lt;code&amp;gt;pAllocParms&amp;lt;/code&amp;gt; pointing at the caller's own '''8-byte stack local''' and &amp;lt;code&amp;gt;paramsSize = 0&amp;lt;/code&amp;gt;; the guest driver does not honour &amp;lt;code&amp;gt;paramsSize&amp;lt;/code&amp;gt;, so it reads '''16-byte''' class params starting there (the upper 8 bytes are the hook's saved &amp;lt;code&amp;gt;rbp&amp;lt;/code&amp;gt;) and copies 16 bytes of reply params back over the same buffer. With the old zeroed reply that copy-back zeroed the saved &amp;lt;code&amp;gt;rbp&amp;lt;/code&amp;gt;; the function's epilogue then loaded &amp;lt;code&amp;gt;rbp = 0&amp;lt;/code&amp;gt; and its next access — reloading a pointer from &amp;lt;code&amp;gt;[rbp-0x38]&amp;lt;/code&amp;gt; — faulted at &amp;lt;code&amp;gt;0xffffffffffffffc8&amp;lt;/code&amp;gt; (the store was the kernel's &amp;lt;code&amp;gt;copy_to_user&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
'''The fix:''' echo the request's params back, forcing only &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;NV_OK&amp;lt;/code&amp;gt;; the copy-back then writes exactly the bytes it read, and the fault disappears — the same thing the real GSP-RM does for these in/out params.&lt;br /&gt;
&lt;br /&gt;
'''The general rule:''' the userspace library is a ''consumer of emulated data''. A wrong reply is worse than a slow one. Work up the reply-fidelity ladder — status-only → coherent zeroed params → coherent values for consumed fields → exact values — and validate each rung with the A/B oracle.&lt;br /&gt;
&lt;br /&gt;
== 6. How to look things up ==&lt;br /&gt;
&lt;br /&gt;
The toolchain is version-agnostic (&amp;lt;code&amp;gt;docs/06&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;tools/cudatool.py info|exports|functions|nearest|crash|delta &amp;amp;lt;lib&amp;amp;gt;&lt;br /&gt;
tools/callwalk.py &amp;amp;lt;callgraph.tsv&amp;amp;gt; callers|callees|chain ...&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''&amp;lt;code&amp;gt;cudatool.py&amp;lt;/code&amp;gt;''' — build id/sections/exports/ABI note (&amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;), symbol map (&amp;lt;code&amp;gt;exports&amp;lt;/code&amp;gt;), function ranges from &amp;lt;code&amp;gt;.eh_frame_hdr&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;functions&amp;lt;/code&amp;gt;), containing function and nearest export for an address (&amp;lt;code&amp;gt;nearest&amp;lt;/code&amp;gt;), dmesg &amp;lt;code&amp;gt;ip&amp;lt;/code&amp;gt; to file vaddr (&amp;lt;code&amp;gt;crash&amp;lt;/code&amp;gt;), and an interface-level diff (&amp;lt;code&amp;gt;delta&amp;lt;/code&amp;gt;).&lt;br /&gt;
* '''&amp;lt;code&amp;gt;callwalk.py&amp;lt;/code&amp;gt;''' — caller/callee trees and shortest call paths over the callgraph index.&lt;br /&gt;
* '''Annotated corpus''' — &amp;lt;code&amp;gt;570.144/annotations/names.tsv&amp;lt;/code&amp;gt; (our name map; exports exact, internals grow over time) and &amp;lt;code&amp;gt;subsystems.tsv&amp;lt;/code&amp;gt;; corpus headers carry the recovered name, file address and direct callers/callees. The generated corpus is not distributed.&lt;br /&gt;
&lt;br /&gt;
'''Address convention (read this before citing an offset).''' Public docs cite '''file virtual addresses''' as &amp;lt;code&amp;gt;libcuda+0x...&amp;lt;/code&amp;gt;. Ghidra loads these binaries at image base &amp;lt;code&amp;gt;0x100000&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;program address = file vaddr + 0x100000&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;tools/&amp;lt;/code&amp;gt; wrappers translate automatically, raw Ghidra scripts do not. An earlier analysis passed file vaddrs straight to Ghidra and decompiled functions 0x100000 too low, so its decompiled-code conclusions were about the wrong functions (its live traces stayed valid). The same applies when transferring a name map to a new driver version.&lt;br /&gt;
&lt;br /&gt;
== 7. Where the detail lives ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Document&lt;br /&gt;
! What it gives you&lt;br /&gt;
|-&lt;br /&gt;
| [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/READ-ME-FIRST.md &amp;lt;code&amp;gt;../userspace/cuda/READ-ME-FIRST.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
| the reading order, fast recipes, and the two findings that change how you debug&lt;br /&gt;
|-&lt;br /&gt;
| [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/docs/01-architecture.md &amp;lt;code&amp;gt;../userspace/cuda/docs/01-architecture.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
| the full layer/object/sync/memory model&lt;br /&gt;
|-&lt;br /&gt;
| [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/docs/02-build-and-execution.md &amp;lt;code&amp;gt;../userspace/cuda/docs/02-build-and-execution.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
| build model, embedded device code, init/threading, what it touches&lt;br /&gt;
|-&lt;br /&gt;
| [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/docs/03-driver-and-gpu-interface.md &amp;lt;code&amp;gt;../userspace/cuda/docs/03-driver-and-gpu-interface.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
| the emulation contract: nodes, ioctls, classes, controls, channels, UVM&lt;br /&gt;
|-&lt;br /&gt;
| [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/docs/04-virtualization-and-emulation.md &amp;lt;code&amp;gt;../userspace/cuda/docs/04-virtualization-and-emulation.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
| NVIDIA vGPU vs Open-IOV, anti-fragility, performance, security&lt;br /&gt;
|-&lt;br /&gt;
| [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/docs/05-570.144-decompilation.md &amp;lt;code&amp;gt;../userspace/cuda/docs/05-570.144-decompilation.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
| the binary map, the crash resolution, and the current engine-topology blocker&lt;br /&gt;
|-&lt;br /&gt;
| [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/docs/06-tooling.md &amp;lt;code&amp;gt;../userspace/cuda/docs/06-tooling.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
| every tool, its usage and its cost&lt;br /&gt;
|-&lt;br /&gt;
| [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/docs/07-version-upgrade-playbook.md &amp;lt;code&amp;gt;../userspace/cuda/docs/07-version-upgrade-playbook.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
| re-running the analysis on a new driver version&lt;br /&gt;
|-&lt;br /&gt;
| [https://git.vgpu.io/open-iov.git/tree/userspace/cuda/docs/08-virtualization-approaches.md &amp;lt;code&amp;gt;../userspace/cuda/docs/08-virtualization-approaches.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
| forwarding options and the honest current stage&lt;br /&gt;
|-&lt;br /&gt;
| [https://git.vgpu.io/open-iov.git/tree/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;]&lt;br /&gt;
| the project documentation front door&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=BAR_Emulation_Specification&amp;diff=23962</id>
		<title>BAR Emulation Specification</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=BAR_Emulation_Specification&amp;diff=23962"/>
		<updated>2026-10-12T04:40:05Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= BAR Emulation Specification (GSP 570.144W) =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' The &amp;lt;code&amp;gt;BAR_TRAP&amp;lt;/code&amp;gt; RPC (type 0x0A) described here is '''not used''': in emulation mode it returns &amp;lt;code&amp;gt;-ENOTSUPP&amp;lt;/code&amp;gt;, and BAR access is synchronous MMIO through the BAR shadow. Guest-visible BAR windows are BAR0 (16 MB register MMIO), BAR1 (256 MB VRAM aperture) and BAR3 (instance window). Canonical documentation: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The GSP firmware implements BAR (Base Address Register) emulation for virtual GPU (vGPU) through the '''BAR_TRAP''' RPC (type 0x0A). The main handler at '''0x04CB8188''' (40 KB) manages BAR1 aperture, forced access, and memory backing. '''This RPC is not used by the live path''': in emulation mode &amp;lt;code&amp;gt;BAR_TRAP&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;-ENOTSUPP&amp;lt;/code&amp;gt;; guest BAR access is handled synchronously as MMIO through the BAR shadow (&amp;lt;code&amp;gt;../kernel/bar_emulation.c&amp;lt;/code&amp;gt;), not via an RPC.&lt;br /&gt;
&lt;br /&gt;
== Key Addresses ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Component&lt;br /&gt;
! Address&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| BAR Trap Handler&lt;br /&gt;
| 0x04CB8188&lt;br /&gt;
| Main emulation logic (40 KB)&lt;br /&gt;
|-&lt;br /&gt;
| RPC Jump Table Entry&lt;br /&gt;
| 0x057675B7&lt;br /&gt;
| BAR_TRAP in secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| String: BAR1&lt;br /&gt;
| 0x0406570E, 0x04085DE0&lt;br /&gt;
| BAR1 identifier&lt;br /&gt;
|-&lt;br /&gt;
| String: Bar1Rest&lt;br /&gt;
| 0x040656DA&lt;br /&gt;
| BAR1 restore state&lt;br /&gt;
|-&lt;br /&gt;
| String: ForceBarAccess&lt;br /&gt;
| 0x040656F2&lt;br /&gt;
| Forced access control&lt;br /&gt;
|-&lt;br /&gt;
| String: Bar1Aperture&lt;br /&gt;
| 0x04065722&lt;br /&gt;
| Aperture configuration&lt;br /&gt;
|-&lt;br /&gt;
| Memory Allocator&lt;br /&gt;
| 0x429B450&lt;br /&gt;
| Arena for BAR backing store&lt;br /&gt;
|-&lt;br /&gt;
| Cache Management&lt;br /&gt;
| 0x429B428&lt;br /&gt;
| Flush/invalidate&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Handler State Machine ==&lt;br /&gt;
&lt;br /&gt;
=== Main Loop (0x04CB8188) ===&lt;br /&gt;
&lt;br /&gt;
The handler runs a continuous event loop processing BAR trap requests:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;while (true) {&lt;br /&gt;
    // Wait for trap event (bitmask in unaff_s5)&lt;br /&gt;
    event = wait_for_bar_event();&lt;br /&gt;
    &lt;br /&gt;
    switch (event &amp;amp;amp; 0x3F) {&lt;br /&gt;
        case 0x01:  // BAR1 write access&lt;br /&gt;
            handle_bar1_write();&lt;br /&gt;
            break;&lt;br /&gt;
        case 0x02:  // BAR1 read access&lt;br /&gt;
            handle_bar1_read();&lt;br /&gt;
            break;&lt;br /&gt;
        case 0x08:  // Aperture configuration&lt;br /&gt;
            handle_aperture_config();&lt;br /&gt;
            break;&lt;br /&gt;
        case 0x10:  // ForceBarAccess&lt;br /&gt;
            handle_force_access();&lt;br /&gt;
            break;&lt;br /&gt;
        case 0x20:  // Bar1Rest (restore)&lt;br /&gt;
            handle_bar1_restore();&lt;br /&gt;
            break;&lt;br /&gt;
        default:&lt;br /&gt;
            return ERROR_UNKNOWN_EVENT;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Event Bitmask ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Bit&lt;br /&gt;
! Event&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| BAR1_WRITE&lt;br /&gt;
| Guest VF wrote to BAR1&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| BAR1_READ&lt;br /&gt;
| Guest VF read from BAR1&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| APERTURE&lt;br /&gt;
| Aperture size/offset change&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| FORCE_ACCESS&lt;br /&gt;
| ForceBarAccess triggered&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| BAR1_REST&lt;br /&gt;
| Restore BAR1 state&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Memory Management ==&lt;br /&gt;
&lt;br /&gt;
=== Allocator Arena (0x429B450) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Allocate backing store for BAR emulation&lt;br /&gt;
void *bar_alloc(size_t size) {&lt;br /&gt;
    // Calls UNK_ram_058A1A9C(0x429B450, size)&lt;br /&gt;
    // Returns pointer in 0x429B000 region&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Free backing store&lt;br /&gt;
void bar_free(void *ptr) {&lt;br /&gt;
    // Calls UNK_ram_05895BF4(0x429B428, ptr)&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocation Sizes ===&lt;br /&gt;
&lt;br /&gt;
* '''Standard BAR1 page''': 0x1000 (4 KB)&lt;br /&gt;
* '''Aperture buffer''': 0x40000 (256 KB) max&lt;br /&gt;
* '''Force access buffer''': 0x1000 (4 KB)&lt;br /&gt;
&lt;br /&gt;
=== Cache Coherency ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Flush cache for DMA&lt;br /&gt;
void bar_cache_flush(void *addr, size_t size) {&lt;br /&gt;
    UNK_ram_05895BF4(0x429B428, addr);&lt;br /&gt;
    UNK_ram_05895BF4(0x429B428, addr + size);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BAR1 Emulation Logic ==&lt;br /&gt;
&lt;br /&gt;
=== Write Path (Event 0x01) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int handle_bar1_write(bar_trap_t *trap) {&lt;br /&gt;
    // 1. Validate offset within aperture&lt;br /&gt;
    if (trap-&amp;amp;gt;offset &amp;amp;gt;= bar1_aperture_size)&lt;br /&gt;
        return ERROR_OVERFLOW;&lt;br /&gt;
    &lt;br /&gt;
    // 2. Check ForceBarAccess flag&lt;br /&gt;
    if (force_bar_access &amp;amp;amp;&amp;amp;amp; !(trap-&amp;amp;gt;flags &amp;amp;amp; FORCE_ALLOWED))&lt;br /&gt;
        return ERROR_PERMISSION;&lt;br /&gt;
    &lt;br /&gt;
    // 3. Translate to backing store&lt;br /&gt;
    uint8_t *backing = bar1_backing + trap-&amp;amp;gt;offset;&lt;br /&gt;
    &lt;br /&gt;
    // 4. Perform write (1/2/4/8 bytes)&lt;br /&gt;
    switch (trap-&amp;amp;gt;size) {&lt;br /&gt;
        case 1: *backing = trap-&amp;amp;gt;value; break;&lt;br /&gt;
        case 2: *(uint16_t*)backing = trap-&amp;amp;gt;value; break;&lt;br /&gt;
        case 4: *(uint32_t*)backing = trap-&amp;amp;gt;value; break;&lt;br /&gt;
        case 8: *(uint64_t*)backing = trap-&amp;amp;gt;value; break;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // 5. Flush to device if needed&lt;br /&gt;
    if (device_needs_flush)&lt;br /&gt;
        bar_cache_flush(backing, trap-&amp;amp;gt;size);&lt;br /&gt;
    &lt;br /&gt;
    return OK;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Read Path (Event 0x02) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int handle_bar1_read(bar_trap_t *trap) {&lt;br /&gt;
    if (trap-&amp;amp;gt;offset &amp;amp;gt;= bar1_aperture_size)&lt;br /&gt;
        return ERROR_OVERFLOW;&lt;br /&gt;
    &lt;br /&gt;
    uint8_t *backing = bar1_backing + trap-&amp;amp;gt;offset;&lt;br /&gt;
    &lt;br /&gt;
    switch (trap-&amp;amp;gt;size) {&lt;br /&gt;
        case 1: *trap-&amp;amp;gt;out_value = *backing; break;&lt;br /&gt;
        case 2: *trap-&amp;amp;gt;out_value = *(uint16_t*)backing; break;&lt;br /&gt;
        case 4: *trap-&amp;amp;gt;out_value = *(uint32_t*)backing; break;&lt;br /&gt;
        case 8: *trap-&amp;amp;gt;out_value = *(uint64_t*)backing; break;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return OK;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Aperture Configuration (Event 0x08) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int handle_aperture_config(bar_config_t *cfg) {&lt;br /&gt;
    // Validate new aperture&lt;br /&gt;
    if (cfg-&amp;amp;gt;size &amp;amp;gt; MAX_APERTURE_SIZE)  // 0x40000&lt;br /&gt;
        return ERROR_INVALID;&lt;br /&gt;
    &lt;br /&gt;
    if (cfg-&amp;amp;gt;offset &amp;amp;amp; 0xFFF)  // Must be 4KB aligned&lt;br /&gt;
        return ERROR_ALIGNMENT;&lt;br /&gt;
    &lt;br /&gt;
    // Reallocate backing store if size changed&lt;br /&gt;
    if (cfg-&amp;amp;gt;size != bar1_aperture_size) {&lt;br /&gt;
        void *new_backing = bar_alloc(cfg-&amp;amp;gt;size);&lt;br /&gt;
        if (!new_backing) return ERROR_NOMEM;&lt;br /&gt;
        &lt;br /&gt;
        // Copy existing data&lt;br /&gt;
        memcpy(new_backing, bar1_backing, &lt;br /&gt;
               min(cfg-&amp;amp;gt;size, bar1_aperture_size));&lt;br /&gt;
        &lt;br /&gt;
        bar_free(bar1_backing);&lt;br /&gt;
        bar1_backing = new_backing;&lt;br /&gt;
        bar1_aperture_size = cfg-&amp;amp;gt;size;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    bar1_aperture_offset = cfg-&amp;amp;gt;offset;&lt;br /&gt;
    return OK;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ForceBarAccess (Event 0x10) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int handle_force_access(force_access_t *fa) {&lt;br /&gt;
    // ForceBarAccess allows hypervisor to bypass VF permissions&lt;br /&gt;
    // Used for live migration, checkpoint/restore&lt;br /&gt;
    &lt;br /&gt;
    force_bar_access = fa-&amp;amp;gt;enable;&lt;br /&gt;
    force_access_vf = fa-&amp;amp;gt;vf_id;&lt;br /&gt;
    force_access_range = fa-&amp;amp;gt;range;&lt;br /&gt;
    &lt;br /&gt;
    // Allocate shadow buffer for forced operations&lt;br /&gt;
    if (fa-&amp;amp;gt;enable) {&lt;br /&gt;
        force_buffer = bar_alloc(0x1000);&lt;br /&gt;
        if (!force_buffer) return ERROR_NOMEM;&lt;br /&gt;
    } else {&lt;br /&gt;
        bar_free(force_buffer);&lt;br /&gt;
        force_buffer = NULL;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return OK;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bar1Rest - State Restore (Event 0x20) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int handle_bar1_restore(restore_state_t *rs) {&lt;br /&gt;
    // Restore BAR1 state from checkpoint&lt;br /&gt;
    // Used during VF live migration&lt;br /&gt;
    &lt;br /&gt;
    bar1_aperture_offset = rs-&amp;amp;gt;aperture_offset;&lt;br /&gt;
    bar1_aperture_size = rs-&amp;amp;gt;aperture_size;&lt;br /&gt;
    force_bar_access = rs-&amp;amp;gt;force_access;&lt;br /&gt;
    &lt;br /&gt;
    // Restore backing store from serialized data&lt;br /&gt;
    if (rs-&amp;amp;gt;backing_size &amp;amp;gt; 0) {&lt;br /&gt;
        void *new_backing = bar_alloc(rs-&amp;amp;gt;backing_size);&lt;br /&gt;
        if (!new_backing) return ERROR_NOMEM;&lt;br /&gt;
        &lt;br /&gt;
        memcpy(new_backing, rs-&amp;amp;gt;backing_data, rs-&amp;amp;gt;backing_size);&lt;br /&gt;
        bar_free(bar1_backing);&lt;br /&gt;
        bar1_backing = new_backing;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return OK;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== vGPU-IO Integration ==&lt;br /&gt;
&lt;br /&gt;
=== Kernel BAR Trap Registration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct gsp_bar_ops {&lt;br /&gt;
    int (*bar_trap)(struct gsp_device *gsp, &lt;br /&gt;
                    struct bar_trap_msg *msg);&lt;br /&gt;
    int (*configure_aperture)(struct gsp_device *gsp,&lt;br /&gt;
                              uint32_t vf_id,&lt;br /&gt;
                              uint64_t offset, uint64_t size);&lt;br /&gt;
    int (*force_access)(struct gsp_device *gsp,&lt;br /&gt;
                        uint32_t vf_id, bool enable);&lt;br /&gt;
    int (*save_state)(struct gsp_device *gsp,&lt;br /&gt;
                      uint32_t vf_id, void *buf, size_t *size);&lt;br /&gt;
    int (*restore_state)(struct gsp_device *gsp,&lt;br /&gt;
                         uint32_t vf_id, void *buf, size_t size);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static const struct gsp_bar_ops gsp_bar_ops = {&lt;br /&gt;
    .bar_trap = gsp_bar_trap_handler,&lt;br /&gt;
    .configure_aperture = gsp_bar_config_aperture,&lt;br /&gt;
    .force_access = gsp_bar_force_access,&lt;br /&gt;
    .save_state = gsp_bar_save_state,&lt;br /&gt;
    .restore_state = gsp_bar_restore_state,&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== VF BAR Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_vf_bar_init(struct gsp_vf *vf) {&lt;br /&gt;
    struct bar_config cfg = {&lt;br /&gt;
        .vf_id = vf-&amp;amp;gt;id,&lt;br /&gt;
        .bar = 1,  // BAR1&lt;br /&gt;
        .aperture_offset = vf-&amp;amp;gt;bar1_offset,&lt;br /&gt;
        .aperture_size = vf-&amp;amp;gt;bar1_size,&lt;br /&gt;
        .flags = BAR_FLAG_COHERENT,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    return gsp_rpc_send(vf-&amp;amp;gt;gsp, RPC_BAR_TRAP, &lt;br /&gt;
                        BAR_SUBCMD_CONFIG, &amp;amp;amp;cfg, sizeof(cfg));&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Live Migration Support ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Save BAR state for migration&lt;br /&gt;
int gsp_vf_bar_save(struct gsp_vf *vf, void *buf, size_t *size) {&lt;br /&gt;
    struct bar_save_msg msg = {&lt;br /&gt;
        .vf_id = vf-&amp;amp;gt;id,&lt;br /&gt;
        .bar = 1,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    return gsp_rpc_send(vf-&amp;amp;gt;gsp, RPC_BAR_TRAP,&lt;br /&gt;
                        BAR_SUBCMD_SAVE, &amp;amp;amp;msg, sizeof(msg),&lt;br /&gt;
                        buf, size);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Restore BAR state on destination&lt;br /&gt;
int gsp_vf_bar_restore(struct gsp_vf *vf, void *buf, size_t size) {&lt;br /&gt;
    struct bar_restore_msg msg = {&lt;br /&gt;
        .vf_id = vf-&amp;amp;gt;id,&lt;br /&gt;
        .bar = 1,&lt;br /&gt;
        .data = buf,&lt;br /&gt;
        .data_size = size,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    return gsp_rpc_send(vf-&amp;amp;gt;gsp, RPC_BAR_TRAP,&lt;br /&gt;
                        BAR_SUBCMD_RESTORE, &amp;amp;amp;msg, sizeof(msg));&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error Handling ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Error&lt;br /&gt;
! Code&lt;br /&gt;
! Recovery&lt;br /&gt;
|-&lt;br /&gt;
| OOM (0x51)&lt;br /&gt;
| Allocator exhausted&lt;br /&gt;
| Shrink aperture, retry&lt;br /&gt;
|-&lt;br /&gt;
| Timeout (0x1E)&lt;br /&gt;
| Cache flush timeout&lt;br /&gt;
| Reset BAR, reinitialize&lt;br /&gt;
|-&lt;br /&gt;
| Invalid (0x1F)&lt;br /&gt;
| Bad aperture config&lt;br /&gt;
| Validate alignment/size&lt;br /&gt;
|-&lt;br /&gt;
| Permission (0xFFFF)&lt;br /&gt;
| ForceAccess violation&lt;br /&gt;
| Check VF permissions&lt;br /&gt;
|-&lt;br /&gt;
| Overflow (0x25)&lt;br /&gt;
| Offset beyond aperture&lt;br /&gt;
| Bounds check in VF driver&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
&lt;br /&gt;
=== Key Registers to Monitor ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;0x04296048  : Global error flag (cRam0000000004296048)&lt;br /&gt;
0x0429B750  : Error status (0x111300 offset)&lt;br /&gt;
0x429B428   : Cache management base&lt;br /&gt;
0x429B450   : Allocator arena base&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Log Strings ===&lt;br /&gt;
&lt;br /&gt;
Search for these in GSP logs:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;BAR1&amp;lt;/code&amp;gt; - BAR1 access&lt;br /&gt;
* &amp;lt;code&amp;gt;Bar1Rest&amp;lt;/code&amp;gt; - State restore&lt;br /&gt;
* &amp;lt;code&amp;gt;ForceBarAccess&amp;lt;/code&amp;gt; - Forced access&lt;br /&gt;
* &amp;lt;code&amp;gt;Bar1Aperture&amp;lt;/code&amp;gt; - Aperture changes&lt;br /&gt;
* &amp;lt;code&amp;gt;Bar1Size&amp;lt;/code&amp;gt; - Size queries&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
* Handler: &amp;lt;code&amp;gt;FUN_ram_04cb8188_ram_04cb8188.c&amp;lt;/code&amp;gt; (40 KB)&lt;br /&gt;
* RPC Type: 0x0A (BAR_TRAP)&lt;br /&gt;
* Jump Table Entry: 0x057675B7&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Address_Reference&amp;diff=23961</id>
		<title>Address Reference</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Address_Reference&amp;diff=23961"/>
		<updated>2026-10-12T04:40:04Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Fix repository links: point to the cgit tree URLs (git.vgpu.io/open-iov.git/tree/...)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Address Reference =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Retained firmware-side address record.''' The tables below list addresses inside the GSP 570.144W firmware image (the firmware-side record), not host implementation details. Current architecture: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/03-gsp-and-gsp-rm.md &amp;lt;code&amp;gt;../docs/03-architecture/03-gsp-and-gsp-rm.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;]. Decompiled files live under &amp;lt;code&amp;gt;firmware/57X-GSP/570.144/decompiled/&amp;lt;/code&amp;gt;.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Firmware Base ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Symbol&lt;br /&gt;
! Address&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FW_BASE&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x04000000&lt;br /&gt;
| Firmware load address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FW_SIZE&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x02000000&lt;br /&gt;
| ~32 MB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Dispatchers ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Address&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| Entry Point&lt;br /&gt;
| 0x04009000&lt;br /&gt;
| 573B&lt;br /&gt;
| Boot entry&lt;br /&gt;
|-&lt;br /&gt;
| Primary Dispatcher&lt;br /&gt;
| 0x057A1AC0&lt;br /&gt;
| 558B&lt;br /&gt;
| Main RPC dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| Secondary Dispatcher&lt;br /&gt;
| 0x04ED39DC&lt;br /&gt;
| 141KB&lt;br /&gt;
| Branch-based dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| Tertiary Dispatcher&lt;br /&gt;
| 0x05723EF4&lt;br /&gt;
| 13KB&lt;br /&gt;
| Additional dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| RPC Jump Table&lt;br /&gt;
| 0x059BE7F4&lt;br /&gt;
| 4.9KB&lt;br /&gt;
| 12 RPC type table&lt;br /&gt;
|-&lt;br /&gt;
| RPC Type Table&lt;br /&gt;
| 0x059BFEB0&lt;br /&gt;
| —&lt;br /&gt;
| Actual handler addresses&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Primary Dispatcher Sub-Commands (Jump Table at 0x057A3AD8) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Subcmd&lt;br /&gt;
! Target&lt;br /&gt;
! Decompiled&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x057A1DB4&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| 0x057A1C18&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| 0x057A39FC&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 0x057A1BCC&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 0x057A1EF4&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 0x057A1E94&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 0x057A3A28&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| 0x057A3A60&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| 0x057A1C6C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| 0x057A3A48&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| 0x057A1F6C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| 0x057A3AC4&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| 0x057A1E10&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| 0x057A3A90&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| 0x057A39BC&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| 0x057A3AAC&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 16&lt;br /&gt;
| 0x057A3A78&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 17&lt;br /&gt;
| 0x057A1CCC&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 18&lt;br /&gt;
| 0x057A39E0&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 19&lt;br /&gt;
| 0x057A1FA8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 20&lt;br /&gt;
| 0x057A2094&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 21&lt;br /&gt;
| 0x057A2074&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 22&lt;br /&gt;
| 0x057A2044&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 23&lt;br /&gt;
| 0x057A20D4&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 24&lt;br /&gt;
| 0x057A20B4&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 25&lt;br /&gt;
| 0x057A1FC8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 26&lt;br /&gt;
| 0x057A2008&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 27&lt;br /&gt;
| 0x057A1FE8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 28&lt;br /&gt;
| 0x057A2024&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 29&lt;br /&gt;
| 0x057A219C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 30&lt;br /&gt;
| 0x057A20FC&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 31&lt;br /&gt;
| 0x057A214C&lt;br /&gt;
| ✅&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Migration Jump Tables ==&lt;br /&gt;
&lt;br /&gt;
=== Table 1: 0x04179ED8 (MIGRATE branch at 0x057A1BDC) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Index&lt;br /&gt;
! Target&lt;br /&gt;
! Decompiled&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x057A2344&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| 0x057A2320&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| 0x057A230C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 0x057A22F8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 0x057A2388&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 0x057A23D8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 0x057A23AC&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| 0x057A2478&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| 0x057A2428&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| 0x057A2454&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| 0x057A2404&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| 0x057A2364&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| 0x057A299C&lt;br /&gt;
| —&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Table 2: 0x04179FBC (MIGRATE branch at 0x057A1D5C) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Index&lt;br /&gt;
! Target&lt;br /&gt;
! Decompiled&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x057A257C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| 0x057A25E4&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| 0x057A24EC&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 0x057A2608&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 0x057A2534&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 0x057A25C0&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 0x057A24A4&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| 0x057A259C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| 0x057A2510&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| 0x057A2558&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| 0x057A24C8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| 0x057A262C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| 0x057A345C&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| 0x057A36D8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| 0x057A35D8&lt;br /&gt;
| ✅&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| 0x057A3658&lt;br /&gt;
| ✅&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== RPC Handlers (from Jump Table at 0x059BFEB0) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! RPC Type&lt;br /&gt;
! Name&lt;br /&gt;
! Handler A&lt;br /&gt;
! Handler B&lt;br /&gt;
|-&lt;br /&gt;
| 0x01&lt;br /&gt;
| ALLOC&lt;br /&gt;
| —&lt;br /&gt;
| —&lt;br /&gt;
|-&lt;br /&gt;
| 0x02&lt;br /&gt;
| FREE&lt;br /&gt;
| —&lt;br /&gt;
| —&lt;br /&gt;
|-&lt;br /&gt;
| 0x03&lt;br /&gt;
| MAP&lt;br /&gt;
| 0x05766AB7&lt;br /&gt;
| 0x05778A37&lt;br /&gt;
|-&lt;br /&gt;
| 0x04&lt;br /&gt;
| UNMAP&lt;br /&gt;
| 0x057669B7&lt;br /&gt;
| 0x05779937&lt;br /&gt;
|-&lt;br /&gt;
| 0x05&lt;br /&gt;
| PIN&lt;br /&gt;
| 0x057664B7&lt;br /&gt;
| 0x0577A3B7&lt;br /&gt;
|-&lt;br /&gt;
| 0x06&lt;br /&gt;
| UNPIN&lt;br /&gt;
| 0x057682B7&lt;br /&gt;
| 0x05779FB7&lt;br /&gt;
|-&lt;br /&gt;
| 0x07&lt;br /&gt;
| SCHEDULE&lt;br /&gt;
| 0x05767F37&lt;br /&gt;
| 0x0575AEB7&lt;br /&gt;
|-&lt;br /&gt;
| 0x08&lt;br /&gt;
| YIELD&lt;br /&gt;
| 0x0575AE37&lt;br /&gt;
| 0x05767337&lt;br /&gt;
|-&lt;br /&gt;
| 0x09&lt;br /&gt;
| NOTIFY&lt;br /&gt;
| 0x0577C8B7&lt;br /&gt;
| 0x05767837&lt;br /&gt;
|-&lt;br /&gt;
| 0x0A&lt;br /&gt;
| BAR_TRAP&lt;br /&gt;
| 0x057675B7&lt;br /&gt;
| —&lt;br /&gt;
|-&lt;br /&gt;
| 0x0B&lt;br /&gt;
| MIGRATE&lt;br /&gt;
| —&lt;br /&gt;
| —&lt;br /&gt;
|-&lt;br /&gt;
| 0x0C&lt;br /&gt;
| DEBUG&lt;br /&gt;
| —&lt;br /&gt;
| —&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Specialized Main Handlers ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Function&lt;br /&gt;
! Address&lt;br /&gt;
! Size&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_alloc_main&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x057E94EC&lt;br /&gt;
| 40 KB&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_schedule_main&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x051EFBF4&lt;br /&gt;
| 1.8 KB&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_bar_trap_handler&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x04CB8188&lt;br /&gt;
| 40 KB&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rpc_pin_handler&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x04ED34B8&lt;br /&gt;
| —&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== WPR Handlers ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Handler&lt;br /&gt;
! Address&lt;br /&gt;
! Size&lt;br /&gt;
|-&lt;br /&gt;
| WPR Handler 1&lt;br /&gt;
| 0x04F00B0C&lt;br /&gt;
| 62 KB&lt;br /&gt;
|-&lt;br /&gt;
| WPR Handler 2&lt;br /&gt;
| 0x04F00C78&lt;br /&gt;
| 62 KB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Memory &amp;amp;amp; Global State ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Symbol&lt;br /&gt;
! Address&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| Global Error Flag&lt;br /&gt;
| 0x04296048&lt;br /&gt;
| &amp;lt;code&amp;gt;cRam0000000004296048&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Error Status Reg&lt;br /&gt;
| 0x0429B750+0x111300&lt;br /&gt;
| Error register&lt;br /&gt;
|-&lt;br /&gt;
| Stack Canary&lt;br /&gt;
| 0x041DC350&lt;br /&gt;
| Frame guard value&lt;br /&gt;
|-&lt;br /&gt;
| Allocator Arena&lt;br /&gt;
| 0x429B000&lt;br /&gt;
| Base&lt;br /&gt;
|-&lt;br /&gt;
| Allocator Entry&lt;br /&gt;
| 0x429B450&lt;br /&gt;
| &amp;lt;code&amp;gt;UNK_ram_058A1A9C&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Cache Manager&lt;br /&gt;
| 0x429B428&lt;br /&gt;
| &amp;lt;code&amp;gt;UNK_ram_05895BF4&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== String References ==&lt;br /&gt;
&lt;br /&gt;
=== BAR Strings ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! String&lt;br /&gt;
! Address&lt;br /&gt;
|-&lt;br /&gt;
| BAR1&lt;br /&gt;
| 0x0406570E, 0x04085DE0&lt;br /&gt;
|-&lt;br /&gt;
| Bar1Rest&lt;br /&gt;
| 0x040656DA&lt;br /&gt;
|-&lt;br /&gt;
| ForceBarAccess&lt;br /&gt;
| 0x040656F2&lt;br /&gt;
|-&lt;br /&gt;
| Bar1Aperture&lt;br /&gt;
| 0x04065722&lt;br /&gt;
|-&lt;br /&gt;
| Bar1Size&lt;br /&gt;
| (referenced)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== WPR Strings ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! String&lt;br /&gt;
! Address&lt;br /&gt;
|-&lt;br /&gt;
| WPR_WRITE_COMPLETE&lt;br /&gt;
| 0x5E478F8&lt;br /&gt;
|-&lt;br /&gt;
| WPR_READ_COMPLETE&lt;br /&gt;
| 0x5E478E0&lt;br /&gt;
|-&lt;br /&gt;
| WPR_WRITE_TIMEOUT&lt;br /&gt;
| 0x5E47898&lt;br /&gt;
|-&lt;br /&gt;
| WPR_READ_TIMEOUT&lt;br /&gt;
| 0x5E47880&lt;br /&gt;
|-&lt;br /&gt;
| NV_WPR_WRITE_COMPLETE&lt;br /&gt;
| 0x5E478C8&lt;br /&gt;
|-&lt;br /&gt;
| NV_WPR_READ_COMPLETE&lt;br /&gt;
| 0x5E478B0&lt;br /&gt;
|-&lt;br /&gt;
| NV_WPR_WRITE_TIMEOUT&lt;br /&gt;
| 0x5E47868&lt;br /&gt;
|-&lt;br /&gt;
| NV_WPR_READ_TIMEOUT&lt;br /&gt;
| 0x5E47850&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== VBIOS Signatures ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Signature&lt;br /&gt;
! Value&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| VBIOS Standard&lt;br /&gt;
| 0xAA55&lt;br /&gt;
| VBIOS header&lt;br /&gt;
|-&lt;br /&gt;
| WPR Enable&lt;br /&gt;
| 0x57464F4E (&amp;quot;WFON&amp;quot;)&lt;br /&gt;
| WPR on&lt;br /&gt;
|-&lt;br /&gt;
| WPR Version&lt;br /&gt;
| 0x5746564E (&amp;quot;WFVN&amp;quot;)&lt;br /&gt;
| WPR version&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Key Function Pointers (Indirect Calls) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Address&lt;br /&gt;
! Function&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| 0x05AB7DA0&lt;br /&gt;
| Logger&lt;br /&gt;
| String logging&lt;br /&gt;
|-&lt;br /&gt;
| 0x05AC4B7C&lt;br /&gt;
| Stack unwind&lt;br /&gt;
| Frame recovery&lt;br /&gt;
|-&lt;br /&gt;
| 0x058A1A9C&lt;br /&gt;
| Allocator&lt;br /&gt;
| Memory alloc&lt;br /&gt;
|-&lt;br /&gt;
| 0x05895BF4&lt;br /&gt;
| Cache flush&lt;br /&gt;
| Cache management&lt;br /&gt;
|-&lt;br /&gt;
| 0x0588F9C4&lt;br /&gt;
| DMA copy&lt;br /&gt;
| Memory copy&lt;br /&gt;
|-&lt;br /&gt;
| 0x05AEC86C&lt;br /&gt;
| Memory read&lt;br /&gt;
| Read from addr&lt;br /&gt;
|-&lt;br /&gt;
| 0x05AE1430&lt;br /&gt;
| Size query&lt;br /&gt;
| Region size&lt;br /&gt;
|-&lt;br /&gt;
| 0x05AF4D30&lt;br /&gt;
| Page fault&lt;br /&gt;
| Page fault handler&lt;br /&gt;
|-&lt;br /&gt;
| 0x05B10C3C&lt;br /&gt;
| Page map&lt;br /&gt;
| Page mapping&lt;br /&gt;
|-&lt;br /&gt;
| 0x05AE9A2C&lt;br /&gt;
| Crypto/verify&lt;br /&gt;
| Integrity check&lt;br /&gt;
|-&lt;br /&gt;
| 0x05AED674&lt;br /&gt;
| WPR check&lt;br /&gt;
| WPR validation&lt;br /&gt;
|-&lt;br /&gt;
| 0x05AED430&lt;br /&gt;
| WPR emulate&lt;br /&gt;
| WPR emulation&lt;br /&gt;
|-&lt;br /&gt;
| 0x05CB30CC&lt;br /&gt;
| Config read&lt;br /&gt;
| Config access&lt;br /&gt;
|-&lt;br /&gt;
| 0x05CB25E0&lt;br /&gt;
| BAR config&lt;br /&gt;
| BAR configuration&lt;br /&gt;
|-&lt;br /&gt;
| 0x05CB23D8&lt;br /&gt;
| BAR map&lt;br /&gt;
| BAR mapping&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Decompiled Output Files ==&lt;br /&gt;
&lt;br /&gt;
The decompiled analysis output is not distributed; the file names below record what the analysis produced (one decompiled function per firmware address).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Category&lt;br /&gt;
! Files&lt;br /&gt;
|-&lt;br /&gt;
| Core&lt;br /&gt;
| entry_ram_04009000.c, FUN_ram_057a1ac0_ram_057a1ac0.c&lt;br /&gt;
|-&lt;br /&gt;
| Sub-commands&lt;br /&gt;
| FUN_ram_057a1bcc_ram_057a1bcc.c ... FUN_ram_057a214c_ram_057a214c.c (32)&lt;br /&gt;
|-&lt;br /&gt;
| Dispatchers&lt;br /&gt;
| FUN_ram_04cc58f8_ram_04cc58f8.c, FUN_ram_04ed39dc_ram_04ed39dc.c, FUN_ram_05723ef4_ram_05723ef4.c&lt;br /&gt;
|-&lt;br /&gt;
| RPC Jump Table&lt;br /&gt;
| FUN_ram_059be7f4_ram_059be7f4.c&lt;br /&gt;
|-&lt;br /&gt;
| BAR&lt;br /&gt;
| FUN_ram_04cb8188_ram_04cb8188.c&lt;br /&gt;
|-&lt;br /&gt;
| WPR&lt;br /&gt;
| FUN_ram_04f00b0c_ram_04f00b0c.c, FUN_ram_04f00c78_ram_04f00c78.c&lt;br /&gt;
|-&lt;br /&gt;
| ALLOC&lt;br /&gt;
| FUN_ram_057e94ec_ram_057e94ec.c, FUN_ram_04d00a18_ram_04d00a18.c, FUN_ram_054a7de0_ram_054a7de0.c&lt;br /&gt;
|-&lt;br /&gt;
| SCHEDULE&lt;br /&gt;
| FUN_ram_051efbf4_ram_051efbf4.c&lt;br /&gt;
|-&lt;br /&gt;
| RPC Handlers&lt;br /&gt;
| FUN_ram_057664b7_ram_057664b7.c ... FUN_ram_0577c8b7_ram_0577c8b7.c (15)&lt;br /&gt;
|-&lt;br /&gt;
| Migration&lt;br /&gt;
| FUN_ram_057a22f8_ram_057a22f8.c ... FUN_ram_057a3658_ram_057a3658.c (28)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Migration Sub-Command Descriptors (Sample) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Handler&lt;br /&gt;
! Returned ID&lt;br /&gt;
! Phase&lt;br /&gt;
|-&lt;br /&gt;
| 0x057A22F8&lt;br /&gt;
| 0x10&lt;br /&gt;
| Prepare&lt;br /&gt;
|-&lt;br /&gt;
| 0x057A2344&lt;br /&gt;
| 0x14&lt;br /&gt;
| Prepare&lt;br /&gt;
|-&lt;br /&gt;
| Others&lt;br /&gt;
| TBD&lt;br /&gt;
| Transfer/Commit&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Main_Page&amp;diff=23960</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Main_Page&amp;diff=23960"/>
		<updated>2026-10-12T04:34:37Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Remove LibVF.IO reference from the landing page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&amp;lt;div style=&amp;quot;border:1px solid #c8ccd1; background:#f8f9fa; padding:0.9em 1.2em; margin-bottom:1em;&amp;quot;&amp;gt;&lt;br /&gt;
'''Open-IOV''' is an open-source virtualization layer for NVIDIA GPUs: it runs '''stock, unmodified NVIDIA drivers inside virtual machines''' — Linux and Windows — with CUDA on hardware you own, '''without proprietary vGPU licenses''', without patching the guest driver, the host driver, the hypervisor or the firmware.&lt;br /&gt;
&lt;br /&gt;
'''''Emulate the interface. Pass through the work. Never patch anyone.'''''&lt;br /&gt;
&lt;br /&gt;
The only new component is one host kernel module (&amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt;), which implements the interface the guest driver expects to talk to — the GPU System Processor and its resource-manager firmware — and arranges for the guest's work to run on real GPU hardware.&lt;br /&gt;
&lt;br /&gt;
'''[[Open-IOV:About|About Open-IOV]]''' · '''[[Community|Community]]''' · '''[[Documentation|Documentation]]'''&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Start here ==&lt;br /&gt;
* '''[[Project Status]]''' — the honest, dated state of the project.&lt;br /&gt;
* '''[[Install and First Run]]''' — fresh host to a stock guest driver in about half an hour.&lt;br /&gt;
* '''[[System Overview]]''' — how Open-IOV works, in one page.&lt;br /&gt;
* '''[[Documentation]]''' — the full index of this wiki.&lt;br /&gt;
* '''[[FAQ]]''' — the questions we get asked most.&lt;br /&gt;
&lt;br /&gt;
== Project status (2026-10-12) ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Area !! State&lt;br /&gt;
|-&lt;br /&gt;
| Emulated vGPU device (PCI, BARs, MSI-X, VFIO mdev) || Working&lt;br /&gt;
|-&lt;br /&gt;
| GSP boot emulation and GSP-RM message queues / RPC || Working&lt;br /&gt;
|-&lt;br /&gt;
| Stock guest driver probe, nvidia-smi (TU104) || Working&lt;br /&gt;
|-&lt;br /&gt;
| CUDA userspace init and the driver-API smoke (ALL OK, 64-byte payload round-trips) || Working&lt;br /&gt;
|-&lt;br /&gt;
| Guest CUDA kernel execution on real hardware || In progress — a forwarded launch reaches the engine queue; engine execution is the frontier&lt;br /&gt;
|-&lt;br /&gt;
| OpenGL / Vulkan, Windows guests, multi-tenancy, migration, performance || Not yet&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The full story, with evidence and the current wall: [[Project Status]] and [[The Execution Frontier]].&lt;br /&gt;
&lt;br /&gt;
== Deep dives ==&lt;br /&gt;
* [[System Overview]] — the architecture before any subsystem&lt;br /&gt;
* [[GSP and GSP-RM]] — the firmware interface we emulate&lt;br /&gt;
* [[The vGSP Execution Plane (vEP)]] — how guest work becomes execution and completion&lt;br /&gt;
* [[The Host Module (vgsp.ko)]] — the module internals&lt;br /&gt;
* [[The Guest Stack and CUDASW]] — what runs unmodified in the guest&lt;br /&gt;
* [[CUDA Userspace Driver]] — the &amp;lt;code&amp;gt;libcuda.so&amp;lt;/code&amp;gt; analysis&lt;br /&gt;
* [[Introduction to GMMU]] — GPU address translation from first principles&lt;br /&gt;
* [[UVM in the Guest]] — unified memory as a correctness oracle&lt;br /&gt;
* [[Physical GPU Backend and Guest Wiring]] — how work reaches real hardware&lt;br /&gt;
* [[The Execution Frontier]] — the leading edge, evidence-led&lt;br /&gt;
* [[Guest Driver Lifecycle: A Field Guide]] — boot to CUDA with real IDs and log signatures&lt;br /&gt;
&lt;br /&gt;
== Firmware interoperability ==&lt;br /&gt;
* [[GSP 570.144W Firmware Analysis]]&lt;br /&gt;
* [[Address Reference]]&lt;br /&gt;
* [[RPC Message Format]] · [[BAR Emulation Specification]] · [[WPR Management]] · [[Migration Protocol]] · [[GSP RPC Emulation]] (historical, superseded)&lt;br /&gt;
* [[risc-v-gsp-rm-debugger]] — the firmware runtime workbench&lt;br /&gt;
&lt;br /&gt;
== Project and ecosystem ==&lt;br /&gt;
* [[Hardware and Software Matrix]] — supported combinations, honestly labelled&lt;br /&gt;
* [[HAAEEP and Collaboration]] — the agent-edge use case and how to work with us&lt;br /&gt;
* [[FAQ]] · [[Glossary]]&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
* Source and issues: [https://git.vgpu.io/open-iov git.vgpu.io/open-iov]&lt;br /&gt;
* Chat: [https://discord.gg/Rb9K9DYxKK Open-IOV Discord]&lt;br /&gt;
&lt;br /&gt;
== About Open-IOV ==&lt;br /&gt;
Open-IOV runs unmodified NVIDIA driver stacks inside virtual machines with GPU compute on hardware you own — no proprietary vGPU license, and no patches to the guest driver, the host driver, the hypervisor or the firmware. The project adds one host kernel module (&amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt;) that implements the interface the guest driver expects to talk to — the GPU System Processor and its resource-manager firmware — and arranges for the guest's work to run on real GPU hardware.&lt;br /&gt;
&lt;br /&gt;
* '''Mission:''' make NVIDIA GPUs fully virtualizable, by anyone, for any hypervisor, without modifying NVIDIA software, firmware or hardware.&lt;br /&gt;
* '''Principles:''' no patches anywhere; honest status carried with dated evidence; an independent, self-contained IP block; durability by owning the interface rather than a snapshot of it.&lt;br /&gt;
* '''Licensing:''' all documentation on this site is [https://creativecommons.org/licenses/by/4.0/ CC-BY-4.0]; the project's code is BSD-3-Clause (GPL-2.0 for the kernel modules); NVIDIA software and firmware are used unmodified and are not redistributed.&lt;br /&gt;
&lt;br /&gt;
'''[[Open-IOV:About|Read more about Open-IOV →]]'''&lt;br /&gt;
&lt;br /&gt;
== About this wiki ==&lt;br /&gt;
This wiki previously hosted documentation from the earlier project era (2021–2023). Those pages are retained for reference under [[Documentation|History]]; current documentation starts at [[Documentation]].&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=VGPU-IO_Integration_Guide&amp;diff=23959</id>
		<title>VGPU-IO Integration Guide</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=VGPU-IO_Integration_Guide&amp;diff=23959"/>
		<updated>2026-10-12T04:29:54Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= vGPU-IO Integration Guide =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' This earlier integration design predates the current stack and is retained for reference only. Canonical documentation: getting started [https://git.vgpu.io/open-iov/blob/master/docs/02-getting-started &amp;lt;code&amp;gt;../docs/02-getting-started/&amp;lt;/code&amp;gt;], host module [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;], developer standards [https://git.vgpu.io/open-iov/blob/master/docs/07-developers &amp;lt;code&amp;gt;../docs/07-developers/&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
This guide covers implementing a Linux kernel driver for vGPU-IO using the GSP 570.144W firmware RPC interface.&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;┌─────────────────────────────────────────────────────────────┐&lt;br /&gt;
│                    vGPU-IO Kernel Driver                     │&lt;br /&gt;
├─────────────────────────────────────────────────────────────┤&lt;br /&gt;
│  gsp_core.c      │  gsp_rpc.c    │  gsp_vf.c               │&lt;br /&gt;
│  - Device probe  │  - RPC client │  - VF lifecycle         │&lt;br /&gt;
│  - BAR mapping   │  - Doorbell   │  - Migration            │&lt;br /&gt;
│  - IRQ/MSI-X     │  - Completion │  - WPR/BAR integration  │&lt;br /&gt;
├─────────────────────────────────────────────────────────────┤&lt;br /&gt;
│                    GSP Firmware (570.144W)                   │&lt;br /&gt;
│  Primary Dispatcher (0x057A1AC0)  │  Secondary (0x04ED39DC) │&lt;br /&gt;
│  BAR Handler (0x04CB8188)         │  WPR Handlers           │&lt;br /&gt;
│  Migration (0x04179ED8/0x04179FBC)│  SCHED/ALLOC/PIN        │&lt;br /&gt;
└─────────────────────────────────────────────────────────────┘&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module Structure ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;drivers/gpu/nvidia/gsp/&lt;br /&gt;
├── gsp.h              # Core definitions&lt;br /&gt;
├── gsp_rpc.h          # RPC message formats&lt;br /&gt;
├── gsp_vf.h           # VF definitions&lt;br /&gt;
├── gsp_bar.h          # BAR emulation&lt;br /&gt;
├── gsp_wpr.h          # WPR management&lt;br /&gt;
├── gsp_migration.h    # Migration protocol&lt;br /&gt;
├── gsp_core.c         # Probe/remove, BAR/IRQ&lt;br /&gt;
├── gsp_rpc.c          # RPC client implementation&lt;br /&gt;
├── gsp_vf.c           # VF create/destroy&lt;br /&gt;
├── gsp_bar.c          # BAR trap handler&lt;br /&gt;
├── gsp_wpr.c          # WPR protect/unprotect&lt;br /&gt;
├── gsp_migration.c    # Live migration&lt;br /&gt;
└── gsp_debugfs.c      # Debug interface&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Core Data Structures ==&lt;br /&gt;
&lt;br /&gt;
=== GSP Device ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct gsp_device {&lt;br /&gt;
    struct pci_dev *pdev;&lt;br /&gt;
    void __iomem *bar0;           // PCIe BAR0 mapping&lt;br /&gt;
    void __iomem *bar1;           // PCIe BAR1 (GSP FW)&lt;br /&gt;
    struct gsp_firmware *fw;      // Firmware image&lt;br /&gt;
    struct gsp_rpc_client *rpc;   // RPC client&lt;br /&gt;
    struct mutex vf_lock;&lt;br /&gt;
    struct idr vf_idr;            // VF ID allocator&lt;br /&gt;
    struct list_head vf_list;&lt;br /&gt;
    struct gsp_debugfs *debugfs;&lt;br /&gt;
    spinlock_t doorbell_lock;&lt;br /&gt;
    uint32_t doorbell_seq;&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== VF (Virtual Function) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct gsp_vf {&lt;br /&gt;
    struct gsp_device *gsp;&lt;br /&gt;
    uint32_t id;                  // VF ID (1-7)&lt;br /&gt;
    struct kref ref;&lt;br /&gt;
    struct mutex lock;&lt;br /&gt;
    mig_state_t mig_state;&lt;br /&gt;
    struct gsp_migration *migration;&lt;br /&gt;
    uint64_t bar1_offset;         // BAR1 aperture offset&lt;br /&gt;
    uint64_t bar1_size;           // BAR1 aperture size&lt;br /&gt;
    uint64_t pt_base;             // Page table base&lt;br /&gt;
    uint64_t pt_size;             // Page table size&lt;br /&gt;
    uint64_t cmd_base;            // Command buffer base&lt;br /&gt;
    uint64_t cmd_size;            // Command buffer size&lt;br /&gt;
    struct gsp_wpr_region *wpr_regions;&lt;br /&gt;
    struct list_head wpr_list;&lt;br /&gt;
    struct gsp_bar_state bar_state;&lt;br /&gt;
    atomic_t refcount;&lt;br /&gt;
    bool active;&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Initialization Sequence ==&lt;br /&gt;
&lt;br /&gt;
=== 1. PCI Probe ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;static int gsp_probe(struct pci_dev *pdev, const struct pci_device_id *id) {&lt;br /&gt;
    struct gsp_device *gsp;&lt;br /&gt;
    int ret;&lt;br /&gt;
    &lt;br /&gt;
    gsp = devm_kzalloc(&amp;amp;amp;pdev-&amp;amp;gt;dev, sizeof(*gsp), GFP_KERNEL);&lt;br /&gt;
    gsp-&amp;amp;gt;pdev = pdev;&lt;br /&gt;
    pci_set_drvdata(pdev, gsp);&lt;br /&gt;
    &lt;br /&gt;
    // Enable PCI device&lt;br /&gt;
    ret = pcim_enable_device(pdev);&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    // Map BARs&lt;br /&gt;
    gsp-&amp;amp;gt;bar0 = pcim_iomap(pdev, 0, 0);&lt;br /&gt;
    gsp-&amp;amp;gt;bar1 = pcim_iomap(pdev, 1, 0);&lt;br /&gt;
    if (!gsp-&amp;amp;gt;bar0 || !gsp-&amp;amp;gt;bar1) return -ENOMEM;&lt;br /&gt;
    &lt;br /&gt;
    // Load firmware&lt;br /&gt;
    ret = gsp_firmware_load(gsp, &amp;quot;gsp-570.144.fwimage.bin&amp;quot;);&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    // Initialize RPC client&lt;br /&gt;
    gsp-&amp;amp;gt;rpc = gsp_rpc_client_init(gsp);&lt;br /&gt;
    if (IS_ERR(gsp-&amp;amp;gt;rpc)) return PTR_ERR(gsp-&amp;amp;gt;rpc);&lt;br /&gt;
    &lt;br /&gt;
    // Setup IRQ/MSI-X&lt;br /&gt;
    ret = gsp_setup_irq(gsp);&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    // Initialize debugfs&lt;br /&gt;
    gsp_debugfs_init(gsp);&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Firmware Loading ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_firmware_load(struct gsp_device *gsp, const char *name) {&lt;br /&gt;
    const struct firmware *fw;&lt;br /&gt;
    int ret;&lt;br /&gt;
    &lt;br /&gt;
    ret = request_firmware(&amp;amp;amp;fw, name, &amp;amp;amp;gsp-&amp;amp;gt;pdev-&amp;amp;gt;dev);&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    // Verify MD5: 13ce12a392a31eeb79a2e6ebd3a4a93a&lt;br /&gt;
    if (!gsp_firmware_verify(fw-&amp;amp;gt;data, fw-&amp;amp;gt;size)) {&lt;br /&gt;
        release_firmware(fw);&lt;br /&gt;
        return -EINVAL;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Load to GSP memory (via BAR1)&lt;br /&gt;
    ret = gsp_firmware_upload(gsp, fw-&amp;amp;gt;data, fw-&amp;amp;gt;size);&lt;br /&gt;
    release_firmware(fw);&lt;br /&gt;
    &lt;br /&gt;
    return ret;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. GSP Boot ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_boot(struct gsp_device *gsp) {&lt;br /&gt;
    // 1. Reset GSP&lt;br /&gt;
    writel(1, gsp-&amp;amp;gt;bar0 + GSP_RESET_REG);&lt;br /&gt;
    msleep(10);&lt;br /&gt;
    writel(0, gsp-&amp;amp;gt;bar0 + GSP_RESET_REG);&lt;br /&gt;
    &lt;br /&gt;
    // 2. Wait for entry point (0x04009000) to signal ready&lt;br /&gt;
    ret = gsp_wait_for_ready(gsp, 5000);  // 5s timeout&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    // 3. Initialize RPC dispatchers&lt;br /&gt;
    ret = gsp_rpc_init_dispatchers(gsp);&lt;br /&gt;
    if (ret) return ret;&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== RPC Client Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== Doorbell Mechanism ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#define GSP_DOORBELL_OFFSET   0x1000&lt;br /&gt;
#define GSP_MSG_RING_SIZE     256&lt;br /&gt;
#define GSP_MSG_MAX_SIZE      256&lt;br /&gt;
&lt;br /&gt;
struct gsp_rpc_client {&lt;br /&gt;
    struct gsp_device *gsp;&lt;br /&gt;
    struct mutex lock;&lt;br /&gt;
    uint32_t seq;&lt;br /&gt;
    wait_queue_head_t wq;&lt;br /&gt;
    struct gsp_msg_ring *ring;&lt;br /&gt;
    struct completion *pending[GSP_MAX_PENDING];&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static int gsp_rpc_send_sync(struct gsp_rpc_client *rpc,&lt;br /&gt;
                             uint32_t rpc_type,&lt;br /&gt;
                             void *payload, size_t payload_size,&lt;br /&gt;
                             void *response, size_t *response_size) {&lt;br /&gt;
    struct gsp_msg msg = {&lt;br /&gt;
        .hdr = {&lt;br /&gt;
            .magic = 0x47535052,&lt;br /&gt;
            .version = 1,&lt;br /&gt;
            .rpc_type = rpc_type,&lt;br /&gt;
            .sequence = atomic_inc_return(&amp;amp;amp;rpc-&amp;amp;gt;seq),&lt;br /&gt;
            .timestamp_ns = ktime_get_ns(),&lt;br /&gt;
            .payload_size = payload_size,&lt;br /&gt;
            .flags = MSG_SYNC,&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    struct completion done;&lt;br /&gt;
    init_completion(&amp;amp;amp;done);&lt;br /&gt;
    &lt;br /&gt;
    mutex_lock(&amp;amp;amp;rpc-&amp;amp;gt;lock);&lt;br /&gt;
    rpc-&amp;amp;gt;pending[msg.hdr.sequence % GSP_MAX_PENDING] = &amp;amp;amp;done;&lt;br /&gt;
    &lt;br /&gt;
    // Copy message to ring buffer&lt;br /&gt;
    memcpy(msg.hdr.payload, payload, payload_size);&lt;br /&gt;
    gsp_ring_write(rpc-&amp;amp;gt;ring, &amp;amp;amp;msg, GSP_MSG_MAX_SIZE);&lt;br /&gt;
    &lt;br /&gt;
    // Ring doorbell&lt;br /&gt;
    writel(1, rpc-&amp;amp;gt;gsp-&amp;amp;gt;bar0 + GSP_DOORBELL_OFFSET);&lt;br /&gt;
    &lt;br /&gt;
    mutex_unlock(&amp;amp;amp;rpc-&amp;amp;gt;lock);&lt;br /&gt;
    &lt;br /&gt;
    // Wait for completion&lt;br /&gt;
    if (!wait_for_completion_timeout(&amp;amp;amp;done, msecs_to_jiffies(5000)))&lt;br /&gt;
        return -ETIMEDOUT;&lt;br /&gt;
    &lt;br /&gt;
    // Copy response&lt;br /&gt;
    if (response &amp;amp;amp;&amp;amp;amp; response_size) {&lt;br /&gt;
        *response_size = min(*response_size, done.payload_size);&lt;br /&gt;
        memcpy(response, done.payload, *response_size);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return done.status;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Completion Handler (ISR) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;static irqreturn_t gsp_isr(int irq, void *data) {&lt;br /&gt;
    struct gsp_device *gsp = data;&lt;br /&gt;
    struct gsp_msg msg;&lt;br /&gt;
    &lt;br /&gt;
    while (gsp_ring_read(gsp-&amp;amp;gt;rpc-&amp;amp;gt;ring, &amp;amp;amp;msg)) {&lt;br /&gt;
        if (msg.hdr.flags &amp;amp;amp; MSG_SYNC) {&lt;br /&gt;
            struct completion *done = &lt;br /&gt;
                gsp-&amp;amp;gt;rpc-&amp;amp;gt;pending[msg.hdr.sequence % GSP_MAX_PENDING];&lt;br /&gt;
            if (done) {&lt;br /&gt;
                done-&amp;amp;gt;status = msg.payload.status;&lt;br /&gt;
                done-&amp;amp;gt;payload_size = msg.hdr.payload_size;&lt;br /&gt;
                memcpy(done-&amp;amp;gt;payload, msg.payload.data, msg.hdr.payload_size);&lt;br /&gt;
                complete(done);&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            // Async notification&lt;br /&gt;
            gsp_handle_notification(gsp, &amp;amp;amp;msg);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return IRQ_HANDLED;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== VF Lifecycle ==&lt;br /&gt;
&lt;br /&gt;
=== Create VF ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_vf_create(struct gsp_device *gsp, uint32_t vf_id,&lt;br /&gt;
                  const struct gsp_vf_config *config) {&lt;br /&gt;
    struct gsp_vf *vf;&lt;br /&gt;
    int ret;&lt;br /&gt;
    &lt;br /&gt;
    mutex_lock(&amp;amp;amp;gsp-&amp;amp;gt;vf_lock);&lt;br /&gt;
    &lt;br /&gt;
    if (idr_alloc(&amp;amp;amp;gsp-&amp;amp;gt;vf_idr, NULL, vf_id, vf_id + 1, GFP_KERNEL) &amp;amp;lt; 0) {&lt;br /&gt;
        ret = -EBUSY;&lt;br /&gt;
        goto unlock;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    vf = kzalloc(sizeof(*vf), GFP_KERNEL);&lt;br /&gt;
    vf-&amp;amp;gt;gsp = gsp;&lt;br /&gt;
    vf-&amp;amp;gt;id = vf_id;&lt;br /&gt;
    kref_init(&amp;amp;amp;vf-&amp;amp;gt;ref);&lt;br /&gt;
    mutex_init(&amp;amp;amp;vf-&amp;amp;gt;lock);&lt;br /&gt;
    INIT_LIST_HEAD(&amp;amp;amp;vf-&amp;amp;gt;wpr_list);&lt;br /&gt;
    &lt;br /&gt;
    // Configure VF resources&lt;br /&gt;
    vf-&amp;amp;gt;bar1_offset = config-&amp;amp;gt;bar1_offset;&lt;br /&gt;
    vf-&amp;amp;gt;bar1_size = config-&amp;amp;gt;bar1_size;&lt;br /&gt;
    vf-&amp;amp;gt;pt_base = config-&amp;amp;gt;pt_base;&lt;br /&gt;
    vf-&amp;amp;gt;pt_size = config-&amp;amp;gt;pt_size;&lt;br /&gt;
    vf-&amp;amp;gt;cmd_base = config-&amp;amp;gt;cmd_base;&lt;br /&gt;
    vf-&amp;amp;gt;cmd_size = config-&amp;amp;gt;cmd_size;&lt;br /&gt;
    &lt;br /&gt;
    // Initialize WPR for VF&lt;br /&gt;
    ret = gsp_vf_wpr_init(vf);&lt;br /&gt;
    if (ret) goto err_wpr;&lt;br /&gt;
    &lt;br /&gt;
    // Initialize BAR for VF&lt;br /&gt;
    ret = gsp_vf_bar_init(vf);&lt;br /&gt;
    if (ret) goto err_bar;&lt;br /&gt;
    &lt;br /&gt;
    list_add(&amp;amp;amp;vf-&amp;amp;gt;list, &amp;amp;amp;gsp-&amp;amp;gt;vf_list);&lt;br /&gt;
    vf-&amp;amp;gt;active = true;&lt;br /&gt;
    &lt;br /&gt;
    mutex_unlock(&amp;amp;amp;gsp-&amp;amp;gt;vf_lock);&lt;br /&gt;
    return 0;&lt;br /&gt;
    &lt;br /&gt;
err_bar:&lt;br /&gt;
    gsp_vf_wpr_fini(vf);&lt;br /&gt;
err_wpr:&lt;br /&gt;
    idr_remove(&amp;amp;amp;gsp-&amp;amp;gt;vf_idr, vf_id);&lt;br /&gt;
    kfree(vf);&lt;br /&gt;
unlock:&lt;br /&gt;
    mutex_unlock(&amp;amp;amp;gsp-&amp;amp;gt;vf_lock);&lt;br /&gt;
    return ret;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Destroy VF ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;void gsp_vf_destroy(struct gsp_vf *vf) {&lt;br /&gt;
    struct gsp_device *gsp = vf-&amp;amp;gt;gsp;&lt;br /&gt;
    uint32_t id = vf-&amp;amp;gt;id;&lt;br /&gt;
    &lt;br /&gt;
    mutex_lock(&amp;amp;amp;gsp-&amp;amp;gt;vf_lock);&lt;br /&gt;
    vf-&amp;amp;gt;active = false;&lt;br /&gt;
    list_del(&amp;amp;amp;vf-&amp;amp;gt;list);&lt;br /&gt;
    mutex_unlock(&amp;amp;amp;gsp-&amp;amp;gt;vf_lock);&lt;br /&gt;
    &lt;br /&gt;
    gsp_vf_bar_fini(vf);&lt;br /&gt;
    gsp_vf_wpr_fini(vf);&lt;br /&gt;
    &lt;br /&gt;
    if (vf-&amp;amp;gt;migration)&lt;br /&gt;
        gsp_migration_cancel(vf-&amp;amp;gt;migration);&lt;br /&gt;
    &lt;br /&gt;
    kref_put(&amp;amp;amp;vf-&amp;amp;gt;ref, gsp_vf_release);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void gsp_vf_release(struct kref *ref) {&lt;br /&gt;
    struct gsp_vf *vf = container_of(ref, struct gsp_vf, ref);&lt;br /&gt;
    kfree(vf);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Memory Management (ALLOC/PIN) ==&lt;br /&gt;
&lt;br /&gt;
=== Allocate VF Memory ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_vf_mem_alloc(struct gsp_vf *vf, &lt;br /&gt;
                     uint64_t size, uint32_t flags,&lt;br /&gt;
                     uint64_t *handle, uint64_t *va) {&lt;br /&gt;
    struct alloc_payload payload = {&lt;br /&gt;
        .size = size,&lt;br /&gt;
        .type = MEM_TYPE_VRAM,&lt;br /&gt;
        .alignment = 0x1000,&lt;br /&gt;
        .va_hint = 0,&lt;br /&gt;
        .flags = flags,&lt;br /&gt;
        .pid = current-&amp;amp;gt;pid,&lt;br /&gt;
        .vf_id = vf-&amp;amp;gt;id,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    struct alloc_response resp;&lt;br /&gt;
    size_t resp_size = sizeof(resp);&lt;br /&gt;
    &lt;br /&gt;
    return gsp_rpc_send_sync(vf-&amp;amp;gt;gsp-&amp;amp;gt;rpc, RPC_ALLOC,&lt;br /&gt;
                             &amp;amp;amp;payload, sizeof(payload),&lt;br /&gt;
                             &amp;amp;amp;resp, &amp;amp;amp;resp_size);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pin Memory for DMA ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_vf_mem_pin(struct gsp_vf *vf, uint64_t handle,&lt;br /&gt;
                   uint64_t offset, uint64_t size,&lt;br /&gt;
                   uint64_t *dma_addr) {&lt;br /&gt;
    struct pin_payload payload = {&lt;br /&gt;
        .handle = handle,&lt;br /&gt;
        .offset = offset,&lt;br /&gt;
        .size = size,&lt;br /&gt;
        .vf_id = vf-&amp;amp;gt;id,&lt;br /&gt;
        .flags = PIN_WRITE | PIN_READ,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    struct pin_response resp;&lt;br /&gt;
    size_t resp_size = sizeof(resp);&lt;br /&gt;
    &lt;br /&gt;
    return gsp_rpc_send_sync(vf-&amp;amp;gt;gsp-&amp;amp;gt;rpc, RPC_PIN,&lt;br /&gt;
                             &amp;amp;amp;payload, sizeof(payload),&lt;br /&gt;
                             &amp;amp;amp;resp, &amp;amp;amp;resp_size);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging &amp;amp;amp; Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Debugfs Interface ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# List VFs&lt;br /&gt;
cat /sys/kernel/debug/gsp/vfs&lt;br /&gt;
&lt;br /&gt;
# VF details&lt;br /&gt;
cat /sys/kernel/debug/gsp/vf/1/status&lt;br /&gt;
&lt;br /&gt;
# RPC statistics&lt;br /&gt;
cat /sys/kernel/debug/gsp/rpc/stats&lt;br /&gt;
&lt;br /&gt;
# BAR state&lt;br /&gt;
cat /sys/kernel/debug/gsp/vf/1/bar&lt;br /&gt;
&lt;br /&gt;
# WPR regions&lt;br /&gt;
cat /sys/kernel/debug/gsp/vf/1/wpr&lt;br /&gt;
&lt;br /&gt;
# Migration status&lt;br /&gt;
cat /sys/kernel/debug/gsp/vf/1/migration&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Trace Events ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# Enable tracing&lt;br /&gt;
echo 1 &amp;amp;gt; /sys/kernel/debug/tracing/events/gsp/enable&lt;br /&gt;
&lt;br /&gt;
# Trace migration&lt;br /&gt;
trace-cmd record -e gsp_mig_phase -e gsp_mig_transfer&lt;br /&gt;
&lt;br /&gt;
# Trace WPR&lt;br /&gt;
trace-cmd record -e gsp_wpr_event&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unit Tests ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// kselftest for gsp-rpc&lt;br /&gt;
static void test_rpc_alloc(void) {&lt;br /&gt;
    struct gsp_vf *vf = create_test_vf();&lt;br /&gt;
    uint64_t handle, va;&lt;br /&gt;
    &lt;br /&gt;
    ASSERT_EQ(gsp_vf_mem_alloc(vf, 4096, 0, &amp;amp;amp;handle, &amp;amp;amp;va), 0);&lt;br /&gt;
    ASSERT_NE(handle, 0);&lt;br /&gt;
    ASSERT_NE(va, 0);&lt;br /&gt;
    &lt;br /&gt;
    gsp_vf_mem_free(vf, handle);&lt;br /&gt;
    destroy_test_vf(vf);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error Handling Checklist ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Scenario&lt;br /&gt;
! Detection&lt;br /&gt;
! Recovery&lt;br /&gt;
|-&lt;br /&gt;
| GSP firmware crash&lt;br /&gt;
| Watchdog timeout&lt;br /&gt;
| Reset GSP, reload FW&lt;br /&gt;
|-&lt;br /&gt;
| RPC timeout&lt;br /&gt;
| Doorbell no response&lt;br /&gt;
| Retry, then VF reset&lt;br /&gt;
|-&lt;br /&gt;
| BAR trap storm&lt;br /&gt;
| Rate limit exceeded&lt;br /&gt;
| Throttle VF&lt;br /&gt;
|-&lt;br /&gt;
| WPR violation&lt;br /&gt;
| Callback storm&lt;br /&gt;
| Quarantine VF&lt;br /&gt;
|-&lt;br /&gt;
| Migration fail&lt;br /&gt;
| Commit verify fail&lt;br /&gt;
| Rollback to source&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Performance Tuning ==&lt;br /&gt;
&lt;br /&gt;
=== RPC Batching ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Batch multiple ALLOCs in single RPC&lt;br /&gt;
struct batch_alloc_payload {&lt;br /&gt;
    uint32_t count;&lt;br /&gt;
    struct alloc_payload allocs[MAX_BATCH];&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Async Completion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Use async RPC for non-critical paths&lt;br /&gt;
gsp_rpc_send_async(rpc, RPC_NOTIFY, payload, size, callback, ctx);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Memory Pool ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Pre-allocate bounce buffers&lt;br /&gt;
struct gsp_bounce_pool {&lt;br /&gt;
    struct page **pages;&lt;br /&gt;
    int count;&lt;br /&gt;
    spinlock_t lock;&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
* GSP Firmware: gsp-570.144.fwimage.bin&lt;br /&gt;
* Base Address: 0x04000000&lt;br /&gt;
* Primary Dispatcher: 0x057A1AC0&lt;br /&gt;
* Secondary Dispatcher: 0x04ED39DC&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=WPR_Management&amp;diff=23958</id>
		<title>WPR Management</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=WPR_Management&amp;diff=23958"/>
		<updated>2026-10-12T04:29:53Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= WPR (Write/Read Protect Region) Management =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' WPR is the '''write-protected region of VRAM reserved for firmware''', not a generic read/write-protect mechanism; the read-protect framing below is historical reverse-engineering material. Canonical documentation: [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
WPR (Write Protect Region / Read Protect Region) provides memory isolation for vGPU by protecting guest memory regions from unauthorized access. The GSP firmware implements WPR through two handlers at '''0x04F00B0C''' and '''0x04F00C78''' (62 KB each).&lt;br /&gt;
&lt;br /&gt;
== Key Addresses ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Handler&lt;br /&gt;
! Address&lt;br /&gt;
! Size&lt;br /&gt;
! Role&lt;br /&gt;
|-&lt;br /&gt;
| WPR Handler 1&lt;br /&gt;
| 0x04F00B0C&lt;br /&gt;
| 62 KB&lt;br /&gt;
| Primary WPR management&lt;br /&gt;
|-&lt;br /&gt;
| WPR Handler 2&lt;br /&gt;
| 0x04F00C78&lt;br /&gt;
| 62 KB&lt;br /&gt;
| Secondary/timeout handling&lt;br /&gt;
|-&lt;br /&gt;
| String Table&lt;br /&gt;
| 60 locations&lt;br /&gt;
| —&lt;br /&gt;
| Completion/timeout strings&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== String References (60 Total) ==&lt;br /&gt;
&lt;br /&gt;
=== Completion Events ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;WPR_WRITE_COMPLETE      0x5E478F8&lt;br /&gt;
WPR_READ_COMPLETE       0x5E478E0&lt;br /&gt;
NV_WPR_WRITE_COMPLETE   0x5E478C8&lt;br /&gt;
NV_WPR_READ_COMPLETE    0x5E478B0&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Timeout Events ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;WPR_WRITE_TIMEOUT       0x5E47898&lt;br /&gt;
WPR_READ_TIMEOUT        0x5E47880&lt;br /&gt;
NV_WPR_WRITE_TIMEOUT    0x5E47868&lt;br /&gt;
NV_WPR_READ_TIMEOUT     0x5E47850&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WPR State Machine ==&lt;br /&gt;
&lt;br /&gt;
=== Handler 1: 0x04F00B0C (Primary) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef enum {&lt;br /&gt;
    WPR_STATE_IDLE = 0,&lt;br /&gt;
    WPR_STATE_WRITE_PENDING = 1,&lt;br /&gt;
    WPR_STATE_READ_PENDING = 2,&lt;br /&gt;
    WPR_STATE_COMPLETE = 3,&lt;br /&gt;
    WPR_STATE_TIMEOUT = 4,&lt;br /&gt;
    WPR_STATE_ERROR = 0xFFFF&lt;br /&gt;
} wpr_state_t;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
    uint64_t region_base;      // Protected region base&lt;br /&gt;
    uint64_t region_size;      // Region size (page-aligned)&lt;br /&gt;
    uint32_t vf_id;            // Owning VF&lt;br /&gt;
    uint32_t flags;            // WPR_WRITE | WPR_READ | WPR_EXECUTE&lt;br /&gt;
    wpr_state_t state;&lt;br /&gt;
    uint64_t timeout_ns;       // Operation timeout&lt;br /&gt;
    void *completion_cb;       // Callback on complete&lt;br /&gt;
    void *timeout_cb;          // Callback on timeout&lt;br /&gt;
} wpr_region_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Operation Flow ===&lt;br /&gt;
&lt;br /&gt;
==== Write Protect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;1. VF requests WPR_WRITE on region [base, base+size)&lt;br /&gt;
2. Handler validates alignment (4KB) and permissions&lt;br /&gt;
3. Programs MMU/IOMMU write-protect bits&lt;br /&gt;
4. Starts timeout timer (configurable)&lt;br /&gt;
5. On GPU write attempt:&lt;br /&gt;
   a. Trap to GSP via page fault&lt;br /&gt;
   b. Check if VF owns region&lt;br /&gt;
   c. If allowed: emulate write, return OK&lt;br /&gt;
   d. If denied: trigger WPR_WRITE_COMPLETE/NV_WPR_WRITE_COMPLETE&lt;br /&gt;
6. On timeout: trigger WPR_WRITE_TIMEOUT/NV_WPR_WRITE_TIMEOUT&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Read Protect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;1. VF requests WPR_READ on region&lt;br /&gt;
2. Programs MMU/IOMMU read-protect bits&lt;br /&gt;
3. On GPU read attempt:&lt;br /&gt;
   a. Trap to GSP&lt;br /&gt;
   b. Return zero/poison data or emulate&lt;br /&gt;
   c. Trigger WPR_READ_COMPLETE/NV_WPR_READ_COMPLETE&lt;br /&gt;
4. On timeout: trigger WPR_READ_TIMEOUT/NV_WPR_READ_TIMEOUT&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== VBIOS Parsing (Handler 2: 0x04F00C78) ==&lt;br /&gt;
&lt;br /&gt;
The WPR handlers parse VBIOS structures for legacy compatibility:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int parse_vbios_for_wpr(void *vbios_ptr, size_t size) {&lt;br /&gt;
    // Search for signatures:&lt;br /&gt;
    // 0xAA55 - Standard VBIOS signature&lt;br /&gt;
    // 0x57464F4E (&amp;quot;WFON&amp;quot;) - WPR enable&lt;br /&gt;
    // 0x5746564E (&amp;quot;WFVN&amp;quot;) - WPR version&lt;br /&gt;
    &lt;br /&gt;
    for (offset = 0; offset &amp;amp;lt; size; offset += 0x1000) {&lt;br /&gt;
        uint32_t sig = *(uint32_t*)(vbios_ptr + offset);&lt;br /&gt;
        &lt;br /&gt;
        if (sig == 0xAA55) {&lt;br /&gt;
            // Check for WPR structures&lt;br /&gt;
            parse_wpr_tables(vbios_ptr + offset);&lt;br /&gt;
        }&lt;br /&gt;
        else if (sig == 0x57464F4E || sig == 0x5746564E) {&lt;br /&gt;
            // WPR enabled in VBIOS&lt;br /&gt;
            wpr_vbios_enabled = true;&lt;br /&gt;
            wpr_vbios_offset = offset;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Integration with GSP Subsystems ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Allocator (0x429B450) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Allocate WPR metadata structures&lt;br /&gt;
wpr_region_t *wpr_alloc_region() {&lt;br /&gt;
    return UNK_ram_058A1A9C(0x429B450, sizeof(wpr_region_t));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Allocate bounce buffers for emulation&lt;br /&gt;
void *wpr_alloc_bounce(size_t size) {&lt;br /&gt;
    return UNK_ram_058A1A9C(0x429B450, size);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DMA/Copy Engine (0x0588F9C4, 0x05AEC86C) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Copy data for WPR emulation&lt;br /&gt;
int wpr_emulate_access(wpr_region_t *rgn, void *dst, void *src, size_t size) {&lt;br /&gt;
    return UNK_ram_0588F9C4(dma_engine, src, dst, size);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logging (0x05AB7DA0) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Log WPR events&lt;br /&gt;
void wpr_log_event(const char *event_str, uint32_t vf_id, uint64_t addr) {&lt;br /&gt;
    UNK_ram_05AB7DA0(1, &amp;amp;amp;event_str);  // Log string&lt;br /&gt;
    UNK_ram_05AB7DA0(2, &amp;amp;amp;vf_id);      // Log VF ID&lt;br /&gt;
    UNK_ram_05AB7DA0(3, &amp;amp;amp;addr);       // Log address&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== vGPU-IO Integration ==&lt;br /&gt;
&lt;br /&gt;
=== Kernel WPR API ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct gsp_wpr_ops {&lt;br /&gt;
    int (*protect_write)(struct gsp_device *gsp, &lt;br /&gt;
                         uint32_t vf_id,&lt;br /&gt;
                         uint64_t base, uint64_t size);&lt;br /&gt;
    int (*protect_read)(struct gsp_device *gsp,&lt;br /&gt;
                        uint32_t vf_id,&lt;br /&gt;
                        uint64_t base, uint64_t size);&lt;br /&gt;
    int (*unprotect)(struct gsp_device *gsp,&lt;br /&gt;
                     uint32_t vf_id,&lt;br /&gt;
                     uint64_t base);&lt;br /&gt;
    int (*set_timeout)(struct gsp_device *gsp,&lt;br /&gt;
                       uint32_t vf_id,&lt;br /&gt;
                       uint64_t timeout_ns);&lt;br /&gt;
    int (*register_callback)(struct gsp_device *gsp,&lt;br /&gt;
                             uint32_t vf_id,&lt;br /&gt;
                             enum wpr_event_type type,&lt;br /&gt;
                             void (*cb)(struct wpr_event *));&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static const struct gsp_wpr_ops gsp_wpr_ops = {&lt;br /&gt;
    .protect_write = gsp_wpr_write_protect,&lt;br /&gt;
    .protect_read = gsp_wpr_read_protect,&lt;br /&gt;
    .unprotect = gsp_wpr_unprotect,&lt;br /&gt;
    .set_timeout = gsp_wpr_set_timeout,&lt;br /&gt;
    .register_callback = gsp_wpr_register_callback,&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== VF WPR Lifecycle ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// VF initialization: register WPR regions&lt;br /&gt;
int gsp_vf_wpr_init(struct gsp_vf *vf) {&lt;br /&gt;
    // Protect VF's page tables&lt;br /&gt;
    gsp_wpr_ops.protect_write(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id,&lt;br /&gt;
                              vf-&amp;amp;gt;pt_base, vf-&amp;amp;gt;pt_size);&lt;br /&gt;
    &lt;br /&gt;
    // Protect VF's command buffers&lt;br /&gt;
    gsp_wpr_ops.protect_write(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id,&lt;br /&gt;
                              vf-&amp;amp;gt;cmd_base, vf-&amp;amp;gt;cmd_size);&lt;br /&gt;
    &lt;br /&gt;
    // Set default timeout (10ms)&lt;br /&gt;
    gsp_wpr_ops.set_timeout(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id, 10000000);&lt;br /&gt;
    &lt;br /&gt;
    // Register completion callbacks&lt;br /&gt;
    gsp_wpr_ops.register_callback(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id,&lt;br /&gt;
                                  WPR_EVENT_WRITE_COMPLETE,&lt;br /&gt;
                                  vf_wpr_write_complete_cb);&lt;br /&gt;
    gsp_wpr_ops.register_callback(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id,&lt;br /&gt;
                                  WPR_EVENT_TIMEOUT,&lt;br /&gt;
                                  vf_wpr_timeout_cb);&lt;br /&gt;
    &lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// VF cleanup&lt;br /&gt;
void gsp_vf_wpr_fini(struct gsp_vf *vf) {&lt;br /&gt;
    gsp_wpr_ops.unprotect(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id, vf-&amp;amp;gt;pt_base);&lt;br /&gt;
    gsp_wpr_ops.unprotect(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id, vf-&amp;amp;gt;cmd_base);&lt;br /&gt;
    // ... unregister callbacks&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Callback Handling ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;static void vf_wpr_write_complete_cb(struct wpr_event *evt) {&lt;br /&gt;
    struct gsp_vf *vf = evt-&amp;amp;gt;vf;&lt;br /&gt;
    &lt;br /&gt;
    // Log the write attempt&lt;br /&gt;
    dev_dbg(vf-&amp;amp;gt;dev, &amp;quot;WPR write complete: VF=%u addr=0x%llx\n&amp;quot;,&lt;br /&gt;
            vf-&amp;amp;gt;id, evt-&amp;amp;gt;address);&lt;br /&gt;
    &lt;br /&gt;
    // If this was a page table update, invalidate TLB&lt;br /&gt;
    if (evt-&amp;amp;gt;address &amp;amp;gt;= vf-&amp;amp;gt;pt_base &amp;amp;amp;&amp;amp;amp; &lt;br /&gt;
        evt-&amp;amp;gt;address &amp;amp;lt; vf-&amp;amp;gt;pt_base + vf-&amp;amp;gt;pt_size) {&lt;br /&gt;
        gsp_tlb_invalidate(vf-&amp;amp;gt;gsp, vf-&amp;amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void vf_wpr_timeout_cb(struct wpr_event *evt) {&lt;br /&gt;
    struct gsp_vf *vf = evt-&amp;amp;gt;vf;&lt;br /&gt;
    &lt;br /&gt;
    dev_warn(vf-&amp;amp;gt;dev, &amp;quot;WPR timeout: VF=%u type=%d addr=0x%llx\n&amp;quot;,&lt;br /&gt;
             vf-&amp;amp;gt;id, evt-&amp;amp;gt;type, evt-&amp;amp;gt;address);&lt;br /&gt;
    &lt;br /&gt;
    // Escalate: reset VF or throttle&lt;br /&gt;
    if (evt-&amp;amp;gt;type == WPR_EVENT_WRITE_TIMEOUT) {&lt;br /&gt;
        gsp_vf_throttle(vf);&lt;br /&gt;
    } else {&lt;br /&gt;
        gsp_vf_reset(vf);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error Codes ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x1E&lt;br /&gt;
| ETIME&lt;br /&gt;
| Operation timed out&lt;br /&gt;
|-&lt;br /&gt;
| 0x1F&lt;br /&gt;
| EDEV&lt;br /&gt;
| Device error&lt;br /&gt;
|-&lt;br /&gt;
| 0x25&lt;br /&gt;
| EOVERFLOW&lt;br /&gt;
| Region too large&lt;br /&gt;
|-&lt;br /&gt;
| 0x37&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Invalid alignment&lt;br /&gt;
|-&lt;br /&gt;
| 0x51&lt;br /&gt;
| ENOMEM&lt;br /&gt;
| Out of memory&lt;br /&gt;
|-&lt;br /&gt;
| 0x56&lt;br /&gt;
| EBUSY&lt;br /&gt;
| Region busy&lt;br /&gt;
|-&lt;br /&gt;
| 0xFFFF&lt;br /&gt;
| EPERM&lt;br /&gt;
| Permission denied&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
&lt;br /&gt;
=== Monitor These Addresses ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;0x04296048  : Global error flag&lt;br /&gt;
0x0429B750+0x111300 : Error status register&lt;br /&gt;
0x05E47850-0x05E478F8 : WPR string table&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GSP Log Patterns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;WPR_WRITE_COMPLETE    VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
WPR_READ_COMPLETE     VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
WPR_WRITE_TIMEOUT     VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
WPR_READ_TIMEOUT      VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
NV_WPR_WRITE_COMPLETE VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
NV_WPR_READ_COMPLETE  VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
NV_WPR_WRITE_TIMEOUT  VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&lt;br /&gt;
NV_WPR_READ_TIMEOUT   VF=&amp;amp;lt;id&amp;amp;gt; ADDR=&amp;amp;lt;addr&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Trace Points ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// In kernel driver&lt;br /&gt;
trace_gsp_wpr_protect(vf_id, base, size, type);&lt;br /&gt;
trace_gsp_wpr_event(vf_id, event_type, address, status);&lt;br /&gt;
trace_gsp_wpr_timeout(vf_id, address, elapsed_ns);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
* Handler 1: &amp;lt;code&amp;gt;FUN_ram_04f00b0c_ram_04f00b0c.c&amp;lt;/code&amp;gt; (62 KB)&lt;br /&gt;
* Handler 2: &amp;lt;code&amp;gt;FUN_ram_04f00c78_ram_04f00c78.c&amp;lt;/code&amp;gt; (62 KB)&lt;br /&gt;
* RPC Types: Handled via primary/secondary dispatchers&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=UVM_in_the_Guest&amp;diff=23957</id>
		<title>UVM in the Guest</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=UVM_in_the_Guest&amp;diff=23957"/>
		<updated>2026-10-12T04:29:53Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= UVM in the Guest =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' What UVM (&amp;lt;code&amp;gt;nvidia_uvm.ko&amp;lt;/code&amp;gt;) does inside the guest, why it is the most demanding consumer of the virtual GPU's semantics, and how it waits. Canonical source: [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/04-uvm.md &amp;lt;code&amp;gt;../docs/03-architecture/04-uvm.md&amp;lt;/code&amp;gt;]; where this page and the docs tree disagree, the docs tree wins.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed with the stock guest driver; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partially working, software bridge in charge; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented default-off; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; planned end state.&lt;br /&gt;
&lt;br /&gt;
== 1. What UVM is ==&lt;br /&gt;
&lt;br /&gt;
UVM provides unified memory and GPU-driven page-fault handling. In practice it is a '''second GPU driver layered on the RM''', owning GPU address spaces and running its own memory-management work on the GPU.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Component&lt;br /&gt;
! Role&lt;br /&gt;
|-&lt;br /&gt;
| VA spaces (&amp;lt;code&amp;gt;uvm_va_space&amp;lt;/code&amp;gt;)&lt;br /&gt;
| per-process GPU address spaces&lt;br /&gt;
|-&lt;br /&gt;
| Channel managers&lt;br /&gt;
| pools of GPU channels (CE, SEC2, GR as needed) for UVM's work&lt;br /&gt;
|-&lt;br /&gt;
| Push buffers / GPFIFO&lt;br /&gt;
| UVM builds and submits its own pushes&lt;br /&gt;
|-&lt;br /&gt;
| Semaphores and trackers&lt;br /&gt;
| UVM waits on GPU-written semaphores to track completion&lt;br /&gt;
|-&lt;br /&gt;
| Page trees&lt;br /&gt;
| GPU page tables for its VA spaces&lt;br /&gt;
|-&lt;br /&gt;
| Fault handling&lt;br /&gt;
| fault buffer plus notification; UVM resolves and replays/cancels faults&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For CUDA, UVM is entered early: &amp;lt;code&amp;gt;cuInit&amp;lt;/code&amp;gt; → driver init → &amp;lt;code&amp;gt;UVM_REGISTER_GPU&amp;lt;/code&amp;gt;. If UVM cannot register the GPU, CUDA does not start — which is why &amp;quot;UVM advances&amp;quot; is the project's primary correctness metric on the way to CUDA.&lt;br /&gt;
&lt;br /&gt;
== 2. The registration path (traced end to end) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;libcuda: UVM_REGISTER_GPU ioctl (0x25)&lt;br /&gt;
  uvm_api_register_gpu -&amp;amp;gt; uvm_va_space_register_gpu -&amp;amp;gt; uvm_gpu_retain_by_uuid&lt;br /&gt;
    nvUvmInterfaceRegisterGpu / GetGpuInfo; alloc_parent_gpu / add_gpu&lt;br /&gt;
      nvUvmInterfaceDeviceCreate          (RM object creation)&lt;br /&gt;
      uvm_hal_init_gpu / get_gpu_caps     (CE caps)&lt;br /&gt;
      uvm_ats_add_gpu / uvm_gpu_init_isr  (fault/interrupt plumbing)&lt;br /&gt;
    init_channel_manager&lt;br /&gt;
      create semaphore pool (sysmem)&lt;br /&gt;
      create channels per CE (GPFIFO + pushbuffer + semaphores)&lt;br /&gt;
      channel_init() -&amp;amp;gt; first push -&amp;amp;gt; semaphore release -&amp;amp;gt; wait&lt;br /&gt;
    uvm_page_tree_init                      (page tables for the VA space)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each stage has a distinct failure signature — see [[Guest Driver Lifecycle: A Field Guide|&amp;lt;code&amp;gt;Driver-Lifecycle-Field-Guide.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
== 3. What UVM requires from the &amp;quot;GPU&amp;quot; ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Requirement&lt;br /&gt;
! Detail&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| GPU identity&lt;br /&gt;
| must match the UUID from RM&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| CE capabilities&lt;br /&gt;
| per-engine support bits; UVM requires &amp;lt;code&amp;gt;supported &amp;amp;amp;&amp;amp;amp; !grce &amp;amp;amp;&amp;amp;amp; sysmem&amp;lt;/code&amp;gt; for CPU_TO_GPU / GPU_TO_CPU channels&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; caps accepted; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; copies forwarded to the physical copy engine&lt;br /&gt;
|-&lt;br /&gt;
| Channel creation&lt;br /&gt;
| RM channel objects with GPFIFO/userd/instance parameters&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Pushes executed&lt;br /&gt;
| first action on a new channel is an init push plus a semaphore-tracked wait&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; software bridge executes memsets, copies and releases; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; CE-class copies forwarded&lt;br /&gt;
|-&lt;br /&gt;
| Page trees&lt;br /&gt;
| UVM initializes page trees with its own pushes; server-owned ranges must be populated by us&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Fault delivery&lt;br /&gt;
| fault buffer plus notification; replay/cancel semantics&lt;br /&gt;
| &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; backend-side observation/relay; guest contract &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Completion semantics&lt;br /&gt;
| tracker values must advance exactly&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Current frontier.''' Context creation and the full CUDA driver-API smoke pass (&amp;lt;code&amp;gt;ALL OK&amp;lt;/code&amp;gt;, copies matched) run end to end. CE-class copies are forwarded to the physical copy engine (default off) with engine-authored releases and a fault relay. For GR, a forwarded guest launch reaches the front-end but the inline launch-descriptor install has not been observed; context validity at dispatch is ruled out ([[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]). The remaining UVM work is completion translation and the guest-side fault replay/cancel contract.&lt;br /&gt;
&lt;br /&gt;
== 4. The discovery that defines the work: how UVM waits ==&lt;br /&gt;
&lt;br /&gt;
UVM's tracker is the single most visible symptom of an unfaithful GPU. It spins, and after 30 seconds it dumps its state:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;uvm_tracker.c:285 Tracker entry for value 1 (sema VA 0x121000000)&lt;br /&gt;
uvm_channel.c:4184 pending push '' started at uvm_channel.c:2535 in channel_init()&lt;br /&gt;
    releasing value 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mechanically, UVM built a push ending in a '''semaphore release''' — a method sequence (CE channel class, e.g. &amp;lt;code&amp;gt;TURING_DMA_COPY_A&amp;lt;/code&amp;gt;) that sets an address and a payload and launches a DMA operation to write the payload to memory — then submitted it and waits for the payload to appear. On real hardware the copy engine writes it; on our device nobody does unless the emulation does. The push we found in guest RAM decodes as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;20010000 0000c5b5   set-object (TURING_DMA_COPY_A)&lt;br /&gt;
2001a000 0000c076   set-object (GP100_UVM_SW)&lt;br /&gt;
20038090 00000001   incrementing-method header: count 3, addr 0x240&lt;br /&gt;
21000000 00000001   lower 32 bits of the semaphore VA; payload (1)&lt;br /&gt;
200180c0 0000000c   LAUNCH_DMA with SEMAPHORE_TYPE=RELEASE_ONE_WORD&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So the emulation's job for this push is: '''write &amp;lt;code&amp;gt;payload&amp;lt;/code&amp;gt; to the memory at the semaphore's GPU VA''', which requires a GPU-VA → guest-PA translation. The host does this through the learned VA→PA map: while the channel's GPFIFO has pending entries it reads each push, decodes the method stream and runs the work (page-table memsets, copies, semaphore releases). When a push page cannot be resolved — or a channel consumes entries without any release landing — it falls back to content: guest RAM is scanned for release groups and pending payloads are applied forward-only. A release is applied only when &amp;lt;code&amp;gt;payload &amp;amp;gt; current&amp;lt;/code&amp;gt;, so recycled push buffers and stale copies are harmless. One pitfall observed live: a semaphore-page VA can flap between two physical pages across map rebuilds; pinning the validated translation fixes the stalled wait.&lt;br /&gt;
&lt;br /&gt;
== 5. The memory model UVM assumes ==&lt;br /&gt;
&lt;br /&gt;
* UVM's semaphore pool is '''system memory''' (&amp;lt;code&amp;gt;UVM_APERTURE_SYS&amp;lt;/code&amp;gt;), one 4 KiB page per channel manager, addressed as 4-byte slots (1024 per page).&lt;br /&gt;
* Each page has a '''GPU VA''' (chosen by the client's RM) and a '''CPU VA''' (a kernel mapping). UVM polls the CPU VA; the GPU writes the GPU VA.&lt;br /&gt;
* Both addresses are recorded in UVM's structures in guest memory — the key that makes translation possible without extra help from the guest.&lt;br /&gt;
* The CPU VA is a direct-map address, so &amp;lt;code&amp;gt;PA = cpu_va - page_offset_base&amp;lt;/code&amp;gt; (verified live: writing the payload there completes the push).&lt;br /&gt;
* Values are per channel and monotonic (1, 2, 3 …); UVM's own check (&amp;lt;code&amp;gt;UVM_GPU_SEMAPHORE_MAX_JUMP&amp;lt;/code&amp;gt;) detects and reports wrong values.&lt;br /&gt;
* The client's page tables for '''server-owned ranges are empty chains''': the client hands us the physical addresses of its page-table levels and expects the server to own the lower levels ([[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 6. Page trees and faults ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;uvm_page_tree_init&amp;lt;/code&amp;gt; initializes a VA space's page tables with pushes on UVM's own channels (memops and page-table writes; the copy engine executes them on real hardware). Fault handling is event-driven: UVM programs a fault buffer (replayable and non-replayable; sizes from &amp;lt;code&amp;gt;INTERNAL_GMMU_GET_STATIC_INFO&amp;lt;/code&amp;gt;, answered by the emulation) and, on a fault, reads the entry, populates the page table and replays or cancels the fault with a &amp;lt;code&amp;gt;MEM_OP&amp;lt;/code&amp;gt; push. Reconciling the guest's memory model with the real GPU's here is the deepest remaining work.&lt;br /&gt;
&lt;br /&gt;
== 7. How to observe UVM ==&lt;br /&gt;
&lt;br /&gt;
In the guest, UVM prints nothing by default:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;echo 1 | sudo tee /sys/module/nvidia_uvm/parameters/uvm_debug_prints&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Messages then appear with the &amp;lt;code&amp;gt;nvidia-uvm:&amp;lt;/code&amp;gt; prefix. Known-good markers, in order: &amp;lt;code&amp;gt;uvm_gpu_retain_by_uuid&amp;lt;/code&amp;gt; → channel manager created → &amp;lt;code&amp;gt;uvm_page_tree_init&amp;lt;/code&amp;gt; pushes → &amp;lt;code&amp;gt;UVM_REGISTER_GPU&amp;lt;/code&amp;gt; returns and CUDA proceeds. Failure signatures characterized live:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Message&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Failed to initialize the channel manager: NV_ERR_NOT_SUPPORTED&amp;lt;/code&amp;gt;&lt;br /&gt;
| CE caps wrong or missing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;stuck waiting&amp;lt;/code&amp;gt; plus &amp;lt;code&amp;gt;Tracker entry ... channel_init()&amp;lt;/code&amp;gt;&lt;br /&gt;
| the push's semaphore was never written&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Assert failed ... unexpected semaphore ... jump from 0x0 to 0x1010101&amp;lt;/code&amp;gt;&lt;br /&gt;
| a wrong payload was written; UVM caught it&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 8. Why UVM is the perfect correctness oracle ==&lt;br /&gt;
&lt;br /&gt;
UVM exercises in minutes what a driver test suite would test in hours: memory allocation, page tables, channel setup, push generation, semaphore semantics, fault handling and error recovery — all with continuous self-checks and loud diagnostics. When UVM registers cleanly and CUDA workloads pass, the device is behaving like a real GPU.&lt;br /&gt;
&lt;br /&gt;
== 9. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/04-uvm.md &amp;lt;code&amp;gt;../docs/03-architecture/04-uvm.md&amp;lt;/code&amp;gt;] — canonical chapter (this page's source).&lt;br /&gt;
* [[The Guest Stack and CUDASW|&amp;lt;code&amp;gt;Guest-Stack-and-CUDASW.md&amp;lt;/code&amp;gt;]], [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]] — the guest stack and the RM objects UVM consumes.&lt;br /&gt;
* [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]] — the userspace half of the contract; [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]], [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]] — how UVM's pushes execute, and the current wall.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/04-implementation/01-known-knowns-and-unknowns.md &amp;lt;code&amp;gt;../docs/04-implementation/01-known-knowns-and-unknowns.md&amp;lt;/code&amp;gt;] — server-owned page tables and the fault contract.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=System_Overview&amp;diff=23956</id>
		<title>System Overview</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=System_Overview&amp;diff=23956"/>
		<updated>2026-10-12T04:29:52Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= System Overview =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' The one page to read if you want to understand ''how Open-IOV works'' before diving into any subsystem. Condensed from [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/01-system-overview.md &amp;lt;code&amp;gt;../docs/03-architecture/01-system-overview.md&amp;lt;/code&amp;gt;] (with [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/09-full-system-picture.md &amp;lt;code&amp;gt;../docs/03-architecture/09-full-system-picture.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/10-interaction-and-scheduling.md &amp;lt;code&amp;gt;../docs/03-architecture/10-interaction-and-scheduling.md&amp;lt;/code&amp;gt;] for the full picture); the docs tree wins on disagreement.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; proven with the stock guest driver; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented default-off; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partial; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; current blocker; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; designed end state.&lt;br /&gt;
&lt;br /&gt;
== 1. The core principle ==&lt;br /&gt;
&lt;br /&gt;
'''Emulate the interface. Pass through the work. Never patch anyone.'''&lt;br /&gt;
&lt;br /&gt;
A virtual GPU is a ''mediated passthrough'' device. The guest must believe it owns a real NVIDIA GPU with a real GPU System Processor running firmware; the host must arrange for the guest's work to execute on real hardware, because emulating compute in software is orders of magnitude too slow to be useful.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EMULATE  (software; the guest expects virtual hardware)&lt;br /&gt;
  PCI configuration space, capability structures, power management&lt;br /&gt;
  BAR0 register interface (shadow, not the physical GPU's BAR0)&lt;br /&gt;
  BAR1 VRAM aperture (guest-visible video memory)&lt;br /&gt;
  GSP firmware boot handshake (FWSEC -&amp;amp;gt; booter -&amp;amp;gt; RISCV -&amp;amp;gt; boot complete)&lt;br /&gt;
  GSP-RM message queues, RPC transport, resource-manager controls&lt;br /&gt;
  event/notification channels; MSI-X injection (via eventfd)&lt;br /&gt;
&lt;br /&gt;
PASS THROUGH  (real hardware; correctness and performance)&lt;br /&gt;
  GPU memory: guest VRAM objects backed by real VRAM       [target]&lt;br /&gt;
  page tables / GMMU state used by the GPU                 [wip]&lt;br /&gt;
  channel execution: guest push buffers on real channels   [gated/wall]&lt;br /&gt;
  compute (CUDA) and, later, 3D/video work                 [wip/planned]&lt;br /&gt;
  DMA, completion and fault interrupts relayed to the guest&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The line between the two is the '''interface boundary''', and it moves as the project matures: early work emulates everything the guest can observe; later work forwards everything that must be fast.&lt;br /&gt;
&lt;br /&gt;
== 2. Layer map ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GUEST&lt;br /&gt;
  application ── CUDA runtime (libcudart) ─┐&lt;br /&gt;
  application ── CUDA driver  (libcuda)   ─┤  userspace: CUDASW stack&lt;br /&gt;
  OpenGL/Vulkan ── libGLX/libvulkan ──────┘&lt;br /&gt;
        │  ioctls / mmaps&lt;br /&gt;
  nvidia.ko (unmodified)  ── RM core, resource server, UVM, modeset/drm&lt;br /&gt;
        │  MMIO + DMA + MSI-X   (a virtual PCIe device)&lt;br /&gt;
════════╪════════════════════════════════════════════════════════&lt;br /&gt;
HYPERVISOR (KVM/QEMU, later Xen/...)  VFIO mdev transport + IOMMU&lt;br /&gt;
        │&lt;br /&gt;
HOST MODULE  vgsp.ko&lt;br /&gt;
  ├─ virtual device: config space, BAR0/BAR1/BAR3 windows, MSI-X&lt;br /&gt;
  ├─ emulation core: GSP boot + GSP-RM (RPC msgq, controls, objects, events)&lt;br /&gt;
  ├─ memory model: guest RAM access, VA&amp;amp;lt;-&amp;amp;gt;PA maps, VRAM backing&lt;br /&gt;
  └─ work path: channel/push forwarding to the physical GPU&lt;br /&gt;
        │ module-owned device + real GSP session&lt;br /&gt;
HOST BACKEND  the GPU's own hardware + GSP firmware, driven by this module&lt;br /&gt;
        │     (the distribution nvidia.ko stays unmodified and unbound in&lt;br /&gt;
        │      this mode)&lt;br /&gt;
        v&lt;br /&gt;
REAL HARDWARE (engines, memory, interrupts)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The guest never contains Open-IOV code; the host driver is unmodified; the hypervisor is unmodified. The only new component is &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. How each side works ==&lt;br /&gt;
&lt;br /&gt;
* '''Guest side.''' The stock driver performs the GSP boot handshake, sets up RPC message queues in guest memory, creates RM objects, programs channels and submits work — exactly as on bare metal ([[The Guest Stack and CUDASW|&amp;lt;code&amp;gt;Guest-Stack-and-CUDASW.md&amp;lt;/code&amp;gt;]], [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]], [[UVM in the Guest|&amp;lt;code&amp;gt;UVM-in-the-Guest.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
* '''Host module.''' &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt; is a VFIO mediated-device driver: it registers a parent on the physical GPU, exposes virtual GPU types, and each mdev is one virtual GPU for one VM. Inside, it presents a plausible Turing-class device (config space, BAR shadows, MSI-X), answers the GSP boot handshake and the RPC protocol with well-formed replies, and maintains the memory model that resolves guest physical addresses to host addresses ([[The Host Module (vgsp.ko)|&amp;lt;code&amp;gt;Host-Module.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
* '''The interface that makes this possible.''' Since Turing, the driver's management path is not ''silicon'', it is ''firmware'': the GSP runs a version of NVIDIA's Resource Manager and the driver talks to it over shared-memory queues with a small RPC protocol. That protocol is small, stable and observable — so the project emulates '''the firmware's interface''' instead of emulating a GPU ([[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]], [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/03-gsp-and-gsp-rm.md &amp;lt;code&amp;gt;../docs/03-architecture/03-gsp-and-gsp-rm.md&amp;lt;/code&amp;gt;]).&lt;br /&gt;
* '''Execution.''' Guest work that must be fast (copies, kernels) is forwarded to a real pipeline driven through the module's own GSP-RM session ([[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]], [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]], [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 4. Data flows ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;MMIO from the guest:&lt;br /&gt;
  guest nvidia.ko writes BAR0 offset X&lt;br /&gt;
    -&amp;amp;gt; KVM exit -&amp;amp;gt; QEMU -&amp;amp;gt; VFIO region write into the mdev&lt;br /&gt;
    -&amp;amp;gt; BAR0 shadow state machine (doorbells, VF registers, notify)&lt;br /&gt;
    -&amp;amp;gt; may wake the emulation thread&lt;br /&gt;
&lt;br /&gt;
RPC from the guest to &amp;quot;firmware&amp;quot;:&lt;br /&gt;
  guest writes a command-queue element into a guest-memory msgq&lt;br /&gt;
    -&amp;amp;gt; doorbell (BAR0)&lt;br /&gt;
    -&amp;amp;gt; emulation thread reads the queue through the hypervisor's guest-RAM&lt;br /&gt;
       accessor, parses the element, dispatches the RPC&lt;br /&gt;
    -&amp;amp;gt; handler produces a reply element in the status queue&lt;br /&gt;
    -&amp;amp;gt; emulation injects an MSI-X interrupt to the guest&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. What runs today ==&lt;br /&gt;
&lt;br /&gt;
# Guest boots, enumerates the virtual PCIe device, binds &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt;.&lt;br /&gt;
# The GSP boot handshake completes against the emulation.&lt;br /&gt;
# Message queues are set up, versions negotiated, RM initialization exchanges complete; object creation, capability queries, vaspaces, channels and the engine inventory are answered with well-formed replies (a small set of control IDs is special-cased with real values; reply fidelity for consumed fields keeps improving).&lt;br /&gt;
# &amp;lt;code&amp;gt;nvidia-smi -L&amp;lt;/code&amp;gt; enumerates the device; CUDA userspace starts; context creation completes; the full driver-API smoke passes (&amp;lt;code&amp;gt;ALL OK&amp;lt;/code&amp;gt;, 64-byte payload round-trips).&lt;br /&gt;
# CE-class copies are forwarded to the physical copy engine (default off) with engine-authored semaphore releases and a fault relay. For GR (graphics/compute), a forwarded guest launch reaches the front-end but the engine has not executed it yet — the current frontier ([[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 6. Where the detail lives ==&lt;br /&gt;
&lt;br /&gt;
* [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]] — the firmware/RM architecture and the transport we emulate.&lt;br /&gt;
* [[The Host Module (vgsp.ko)|&amp;lt;code&amp;gt;Host-Module.md&amp;lt;/code&amp;gt;]] — the module's internals.&lt;br /&gt;
* [[The Guest Stack and CUDASW|&amp;lt;code&amp;gt;Guest-Stack-and-CUDASW.md&amp;lt;/code&amp;gt;]], [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]] — the guest side.&lt;br /&gt;
* [[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]], [[UVM in the Guest|&amp;lt;code&amp;gt;UVM-in-the-Guest.md&amp;lt;/code&amp;gt;]] — memory and translation.&lt;br /&gt;
* [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]], [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]], [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]] — work and execution.&lt;br /&gt;
* [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]] — supported combinations and portability.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/01-system-overview.md &amp;lt;code&amp;gt;../docs/03-architecture/01-system-overview.md&amp;lt;/code&amp;gt;] and the rest of the architecture corpus in the repository.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Risc-v-gsp-rm-debugger&amp;diff=23955</id>
		<title>Risc-v-gsp-rm-debugger</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Risc-v-gsp-rm-debugger&amp;diff=23955"/>
		<updated>2026-10-12T04:29:52Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= risc-v-gsp-rm-debugger =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' risc-v-gsp-rm-debugger runs GSP/uproc firmware off-hardware in a controllable RISC-V machine, instruments it with Frida-like primitives, and records durable sessions so firmware behaviour can be captured and compared with evidence instead of anecdotes. Canonical sources: [https://git.vgpu.io/open-iov/blob/master/docs/05-operations/03-risc-v-gsp-rm-vm.md &amp;lt;code&amp;gt;../docs/05-operations/03-risc-v-gsp-rm-vm.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov/blob/master/docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md &amp;lt;code&amp;gt;../docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md&amp;lt;/code&amp;gt;]; if this page and the docs tree disagree, the docs tree wins.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Development-only.''' Host-side tooling that is never shipped, never a driver dependency and never present in a guest; interfaces and file formats may change without notice.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; recorded QEMU sessions; &amp;lt;code&amp;gt;[design]&amp;lt;/code&amp;gt; device model and custom simulator are roadmap.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. What it is ==&lt;br /&gt;
&lt;br /&gt;
risc-v-gsp-rm-debugger makes the firmware's '''runtime behaviour''' inspectable. It boots GSP/uproc firmware in &amp;lt;code&amp;gt;qemu-system-riscv64&amp;lt;/code&amp;gt; (or a deterministic native interpreter) and offers Frida-like primitives on top:&lt;br /&gt;
&lt;br /&gt;
* breakpoints and enter/leave hooks (RV64 ABI aware); watchpoints on firmware variables;&lt;br /&gt;
* memory read/write/hexdump/search, structure decoding, snapshot diffing;&lt;br /&gt;
* recorded sessions: a replayable event stream plus memory dumps;&lt;br /&gt;
* remote calls and run-to-cursor (execute until a chosen address);&lt;br /&gt;
* injection: build a position-independent RV64 service, load it into the running firmware and dispatch to it;&lt;br /&gt;
* declarative probe specs, a plugin API, and a Ghidra bridge for symbol export, hit annotation and decompiler-driven execution.&lt;br /&gt;
&lt;br /&gt;
Its purpose is '''capturing how the firmware server behaves, repeatably and safely''', so emulation changes can be measured against recorded evidence and can survive GSP version, device and architecture churn. The tooling lives under &amp;lt;code&amp;gt;open-iov/debug/risc-v-gsp-rm-vm/&amp;lt;/code&amp;gt;, with its own documentation set (design, usage, scripting, plugins, bridges, accuracy, portability, roadmap).&lt;br /&gt;
&lt;br /&gt;
== 2. What it is not ==&lt;br /&gt;
&lt;br /&gt;
* '''Not a GSP boot environment.''' QEMU &amp;lt;code&amp;gt;virt&amp;lt;/code&amp;gt; has no falcon windows, WPR2, CSB/TRANSCOM, PMU, timers or FB DMA. &amp;lt;code&amp;gt;probe&amp;lt;/code&amp;gt; reports exactly where the real image first diverges (for the TU104 570.144 image: a load-access fault at firmware vaddr &amp;lt;code&amp;gt;0x4009014&amp;lt;/code&amp;gt; reading &amp;lt;code&amp;gt;0x2000000000000A00&amp;lt;/code&amp;gt;) — expected data, not a boot. A device model is a roadmap item, not a claim.&lt;br /&gt;
* '''Not a timing model.''' Do not infer latency, jitter or concurrency behaviour from it; its in-scope conclusions are execution flow and memory side effects.&lt;br /&gt;
* '''Not a replacement for Ghidra or the guest diagnostics.''' Ghidra answers ''what is the code''; risc-v-gsp-rm-debugger answers ''what did it do''; the guest driver remains the oracle for guest-side behaviour.&lt;br /&gt;
* '''Not a hardware or security tool.''' It never attaches to a real GPU, a guest, a kernel module or an mdev, and it is never a security or confidentiality boundary.&lt;br /&gt;
&lt;br /&gt;
== 3. Where it fits ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Layer&lt;br /&gt;
! Tool&lt;br /&gt;
! Question answered&lt;br /&gt;
|-&lt;br /&gt;
| Static&lt;br /&gt;
| Ghidra and the decompilation corpus&lt;br /&gt;
| what is the code?&lt;br /&gt;
|-&lt;br /&gt;
| Guest driver&lt;br /&gt;
| guest diagnostics, ptrace tracing&lt;br /&gt;
| what did the driver request?&lt;br /&gt;
|-&lt;br /&gt;
| '''Firmware runtime'''&lt;br /&gt;
| '''risc-v-gsp-rm-debugger'''&lt;br /&gt;
| '''what does the firmware server do, repeatably and safely?'''&lt;br /&gt;
|-&lt;br /&gt;
| Physical backend&lt;br /&gt;
| supervised hardware sessions, module logs&lt;br /&gt;
| what did real silicon / the real GSP-RM do?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The intended measurement loop: capture the real backend's RPC behaviour, run the same stimulus in risc-v-gsp-rm-debugger, and compare the recorded sessions with the tool's accuracy metrics. A simulator observation is evidence about the firmware, not about silicon; anything that would change the product is reproduced on a physical reference first.&lt;br /&gt;
&lt;br /&gt;
== 4. Quickstart ==&lt;br /&gt;
&lt;br /&gt;
Requirements: Linux, Python 3.10+ (standard library only), &amp;lt;code&amp;gt;qemu-system-riscv64&amp;lt;/code&amp;gt; (Ubuntu package &amp;lt;code&amp;gt;qemu-system-misc&amp;lt;/code&amp;gt;), &amp;lt;code&amp;gt;clang&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;lld&amp;lt;/code&amp;gt;. No GPU, no driver and no kernel module are touched. From the repository root:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;cd debug/risc-v-gsp-rm-vm&lt;br /&gt;
./risc-v-gsp-rm-debugger.sh info     # environment check: QEMU, toolchain, paths&lt;br /&gt;
make demo &amp;amp;amp;&amp;amp;amp; make sdk                # build the bundled RV64 uproc demo and the injection SDK&lt;br /&gt;
./risc-v-gsp-rm-debugger.sh demo     # canned run: boot, hooks, watchpoints, session&lt;br /&gt;
./risc-v-gsp-rm-debugger.sh analyze dumps/&amp;amp;lt;printed-session-dir&amp;amp;gt;&lt;br /&gt;
./risc-v-gsp-rm-debugger.sh probe    # real GSP image: report the first divergence&lt;br /&gt;
./risc-v-gsp-rm-debugger.sh inject   # load and invoke a position-independent service&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What &amp;quot;good&amp;quot; looks like: &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; reports QEMU and the demo paths; &amp;lt;code&amp;gt;demo&amp;lt;/code&amp;gt; prints hook/branch lines and a session directory under &amp;lt;code&amp;gt;dumps/&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;analyze&amp;lt;/code&amp;gt; renders hook/watch/breakpoint events and a coherent summary; &amp;lt;code&amp;gt;probe&amp;lt;/code&amp;gt; reports a bounded first divergence (expected data, not a boot); &amp;lt;code&amp;gt;inject&amp;lt;/code&amp;gt; returns matching values on the direct and firmware-dispatched invocation paths.&lt;br /&gt;
&lt;br /&gt;
A large test suite (hundreds of tests) is run with &amp;lt;code&amp;gt;make test&amp;lt;/code&amp;gt;, covering unit tests plus live-QEMU smoke runs.&lt;br /&gt;
&lt;br /&gt;
== 5. The primitives ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Primitive&lt;br /&gt;
! Use it for&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;breakpoint&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;hook&amp;lt;/code&amp;gt;&lt;br /&gt;
| did this function run? with what arguments and return value?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;watch&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;w&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;)&lt;br /&gt;
| when did this field change, and from which store PC?&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;run_until&amp;lt;/code&amp;gt;&lt;br /&gt;
| bounded observation; stop at a chosen address&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt;&lt;br /&gt;
| remote call to unit-test a function in isolation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;step&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;note&amp;lt;/code&amp;gt;&lt;br /&gt;
| single-step with dispatch; annotate the event stream&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Memory.read/write/hexdump/search/snapshot/diff&amp;lt;/code&amp;gt;&lt;br /&gt;
| inspect and diff memory regions&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SymbolDB&amp;lt;/code&amp;gt;&lt;br /&gt;
| resolve file/program/runtime addresses across sources&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Recorder&amp;lt;/code&amp;gt;&lt;br /&gt;
| write the durable session (events, snapshots, blobs)&lt;br /&gt;
|-&lt;br /&gt;
| injection SDK&lt;br /&gt;
| load, register and invoke your own position-independent RV64 service&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Instructions between stops are invisible unless a trace is on (a TCG plugin on QEMU, or &amp;lt;code&amp;gt;--trace&amp;lt;/code&amp;gt; on the native backend). Two backends — QEMU-RSP and the native interpreter — satisfy the same session API, so scripts, probes, plugins, recordings and comparisons survive a backend change.&lt;br /&gt;
&lt;br /&gt;
== 6. Fidelity levels (what a result can mean) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Level&lt;br /&gt;
! Property&lt;br /&gt;
! risc-v-gsp-rm-debugger today&lt;br /&gt;
|-&lt;br /&gt;
| '''L0'''&lt;br /&gt;
| instruction semantics&lt;br /&gt;
| high (QEMU TCG, same ISA family)&lt;br /&gt;
|-&lt;br /&gt;
| '''L1'''&lt;br /&gt;
| memory behaviour&lt;br /&gt;
| high for RAM-resident code, conditional on mapping&lt;br /&gt;
|-&lt;br /&gt;
| '''L2'''&lt;br /&gt;
| time / concurrency&lt;br /&gt;
| '''not modelled''' — never claim&lt;br /&gt;
|-&lt;br /&gt;
| '''L3'''&lt;br /&gt;
| device environment (falcon, WPR2, CSB, PMU, timers, DMA, IRQ)&lt;br /&gt;
| '''absent''' — device model is roadmap&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A simulator observation is evidence about the firmware, not about silicon. Never quote a session for timing, interrupt, security or confidentiality claims; zero hits in a run are a coverage fact, not proof that code is dead.&lt;br /&gt;
&lt;br /&gt;
== 7. Sessions as evidence ==&lt;br /&gt;
&lt;br /&gt;
Every run records a session directory (format &amp;lt;code&amp;gt;greeneye-session/1&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dumps/&amp;amp;lt;stamp&amp;amp;gt;-&amp;amp;lt;uuid&amp;amp;gt;-&amp;amp;lt;name&amp;amp;gt;/&lt;br /&gt;
  session.json        format, name, counts, snapshot inventory, meta&lt;br /&gt;
  events.jsonl        append-only event stream (hooks, watches, memory, notes)&lt;br /&gt;
  snapshots/*.bin.z   zlib-compressed region captures with sha256&lt;br /&gt;
  blobs/*             QEMU logs, instruction/access traces, extra captures&lt;br /&gt;
  summary.md          rendered analysis&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules that make a session usable as evidence:&lt;br /&gt;
&lt;br /&gt;
# '''Record with a fixed stimulus.''' The same script, seed, budgets and image hash make runs comparable; a self-comparison must be empty.&lt;br /&gt;
# '''Annotate as you go.''' Explain inside the session what was asked and what was changed; a chat log is not evidence.&lt;br /&gt;
# '''Attach the provenance.''' Firmware SHA-256, version string, symbol DB source/hash/bias, and the exact command or script.&lt;br /&gt;
# '''Keep the directory together.''' &amp;lt;code&amp;gt;session.json&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;events.jsonl&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;snapshots/&amp;lt;/code&amp;gt; + blobs are one artifact; a copied event stream alone is not evidence.&lt;br /&gt;
# '''State the fidelity.''' Say which of L0/L1 was exercised and name the reference capture; do not silently waive L2/L3 gaps.&lt;br /&gt;
# '''Report deltas honestly.''' Every remaining delta between two runs is explained or listed as open; an empty unexplained-delta list is a claim that must be earned.&lt;br /&gt;
# '''Prefer an A/B pair.''' Static reading is a hypothesis; a recorded session is evidence; at least two comparable runs are a conclusion.&lt;br /&gt;
&lt;br /&gt;
== 8. Safety and status ==&lt;br /&gt;
&lt;br /&gt;
* '''Simulator only.''' The tools launch their own QEMU or native machine against the bundled demo or an explicitly allowed re-hosted ELF; they never attach to hardware, a guest, a kernel module, an mdev or an existing debugger stub.&lt;br /&gt;
* '''No guest, no hardware, no product.''' Nothing runs in a guest; injected services are prototypes, not shipped code; product changes go through the host module and a supervised physical confirmation.&lt;br /&gt;
* '''Bounded everywhere.''' Runs have durations and stop caps; reads and snapshots have size caps; a wedged target is left stopped and restarted clean rather than poked.&lt;br /&gt;
* '''Local only.''' The Ghidra bridge is a localhost transport, unauthenticated by design; never expose it on a network interface.&lt;br /&gt;
* '''No confidentiality claims.''' The tool is a study environment; never use injection to defeat a hardware security boundary.&lt;br /&gt;
* '''Status.''' The audited v0.1 surfaces are the CLI and the session format. Working and live-verified: hooks/watchpoints, memory tools, sessions, declarative probes, plugins, remote calls, run-to-cursor, the injection SDK, the Ghidra bridges, the first-fault probe and the instruction/access trace. The device model, the custom simulator and serving full host message traffic remain roadmap; porting and packaging scaffolds are pilot-status. Treat interface changes as reviewed events.&lt;br /&gt;
&lt;br /&gt;
== 9. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/05-operations/03-risc-v-gsp-rm-vm.md &amp;lt;code&amp;gt;../docs/05-operations/03-risc-v-gsp-rm-vm.md&amp;lt;/code&amp;gt;] — project-level purpose, status and limits.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md &amp;lt;code&amp;gt;../docs/05-operations/04-risc-v-gsp-rm-debugger-user-guide.md&amp;lt;/code&amp;gt;] — the single user front door.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/05-operations/02-debugging-and-maintenance-workflows.md &amp;lt;code&amp;gt;../docs/05-operations/02-debugging-and-maintenance-workflows.md&amp;lt;/code&amp;gt;] — captures, failure taxonomy and upgrade workflows.&lt;br /&gt;
* [[GSP 570.144W Firmware Analysis|&amp;lt;code&amp;gt;GSP-570.144W-Firmware-Analysis.md&amp;lt;/code&amp;gt;]] and [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]] — the firmware image and architecture the sessions exercise.&lt;br /&gt;
* [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]] and [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]] — the client side of the RPC traffic and the supervised backend the simulator complements.&lt;br /&gt;
* [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] and [https://git.vgpu.io/open-iov/blob/master/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;] — honest overall status and the documentation front door.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Glossary&amp;diff=23954</id>
		<title>Glossary</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Glossary&amp;diff=23954"/>
		<updated>2026-10-12T04:29:51Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Glossary =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' The terms used across this wiki, the project's documents and its logs. Condensed from [https://git.vgpu.io/open-iov/blob/master/docs/09-reference/glossary-and-faq.md &amp;lt;code&amp;gt;../docs/09-reference/glossary-and-faq.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement. For questions, see [[FAQ|&amp;lt;code&amp;gt;FAQ.md&amp;lt;/code&amp;gt;]].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== GPU, driver and virtualization ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Term&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| '''BAR0 / BAR1 / BAR3'''&lt;br /&gt;
| PCI BAR windows of the GPU: register interface (16 MB), VRAM aperture (256 MB), instance/PRAMIN window.&lt;br /&gt;
|-&lt;br /&gt;
| '''CUDASW'''&lt;br /&gt;
| The family of NVIDIA user-space software between applications and the driver: &amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;libcudart&amp;lt;/code&amp;gt;, the JIT compiler, the fatbinary loader, and friends.&lt;br /&gt;
|-&lt;br /&gt;
| '''Doorbell'''&lt;br /&gt;
| A register or memory location a driver writes to signal &amp;quot;new work is available&amp;quot; for a channel or queue.&lt;br /&gt;
|-&lt;br /&gt;
| '''mdev'''&lt;br /&gt;
| Mediated device: the kernel mechanism that turns a physical device into virtual instances (VFIO).&lt;br /&gt;
|-&lt;br /&gt;
| '''vGPU'''&lt;br /&gt;
| Virtual GPU: the device this project presents to a guest.&lt;br /&gt;
|-&lt;br /&gt;
| '''SRIOV / VF'''&lt;br /&gt;
| Single-root I/O virtualization / virtual functions (hardware partitioning).&lt;br /&gt;
|-&lt;br /&gt;
| '''IOMMU / SMMU'''&lt;br /&gt;
| Platform DMA translation and isolation (Intel VT-d / AMD-Vi / ARM SMMU).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== GSP, firmware and the RM ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Term&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| '''GSP'''&lt;br /&gt;
| GPU System Processor: the embedded RISC-V (RV64IMAC) that runs firmware containing the Resource Manager.&lt;br /&gt;
|-&lt;br /&gt;
| '''GSP-RM'''&lt;br /&gt;
| The Resource Manager running on the GSP (the &amp;quot;self-hosted RM&amp;quot;).&lt;br /&gt;
|-&lt;br /&gt;
| '''RM / RM API'''&lt;br /&gt;
| NVIDIA's Resource Manager and the API used to allocate objects and issue controls.&lt;br /&gt;
|-&lt;br /&gt;
| '''RMCore'''&lt;br /&gt;
| The RM's object system: classes, handles, parents, methods.&lt;br /&gt;
|-&lt;br /&gt;
| '''resserv / resource server'''&lt;br /&gt;
| The RM component that owns allocation authority, privileges and lifetimes.&lt;br /&gt;
|-&lt;br /&gt;
| '''FWSEC'''&lt;br /&gt;
| Firmware security processor stage of the GSP boot sequence.&lt;br /&gt;
|-&lt;br /&gt;
| '''WPR'''&lt;br /&gt;
| Write-Protected Region: the VRAM area reserved for firmware.&lt;br /&gt;
|-&lt;br /&gt;
| '''MSGQ'''&lt;br /&gt;
| The GSP message-queue transport: shared-memory element rings with a page table, plus doorbells.&lt;br /&gt;
|-&lt;br /&gt;
| '''VGX version'''&lt;br /&gt;
| The version the guest announces during RPC negotiation; it selects message layouts.&lt;br /&gt;
|-&lt;br /&gt;
| '''Reply fidelity'''&lt;br /&gt;
| How completely an emulated reply matches what real hardware returns, as a ladder: status-only → coherent zeroed params → coherent values for consumed fields → exact values.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Execution engines and memory ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Term&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| '''CE'''&lt;br /&gt;
| Copy Engine: a DMA engine; also used for UVM's internal work.&lt;br /&gt;
|-&lt;br /&gt;
| '''GR'''&lt;br /&gt;
| The graphics/compute engine that executes shaders (graphics pipelines and CUDA kernels).&lt;br /&gt;
|-&lt;br /&gt;
| '''SEC2'''&lt;br /&gt;
| Secure copy engine used by UVM for protected operations.&lt;br /&gt;
|-&lt;br /&gt;
| '''GPFIFO'''&lt;br /&gt;
| GPU FIFO: a ring of entries, each pointing to a push buffer for a channel.&lt;br /&gt;
|-&lt;br /&gt;
| '''Push buffer'''&lt;br /&gt;
| A stream of method calls (engine commands) submitted via a GPFIFO.&lt;br /&gt;
|-&lt;br /&gt;
| '''PBDMA'''&lt;br /&gt;
| The push-buffer DMA engine in the host scheduler that fetches and executes push buffers.&lt;br /&gt;
|-&lt;br /&gt;
| '''QMD'''&lt;br /&gt;
| Queue Meta Data: the per-launch descriptor a GR channel reads to execute a kernel grid.&lt;br /&gt;
|-&lt;br /&gt;
| '''USERD'''&lt;br /&gt;
| Per-channel control block in VRAM: PUT/GET pointers and control state.&lt;br /&gt;
|-&lt;br /&gt;
| '''Runlist'''&lt;br /&gt;
| The scheduler's list of channels eligible to run.&lt;br /&gt;
|-&lt;br /&gt;
| '''TSG'''&lt;br /&gt;
| Time-Slice Group: channels sharing a scheduling slot.&lt;br /&gt;
|-&lt;br /&gt;
| '''Engine record / engine list'''&lt;br /&gt;
| The per-engine descriptors (kind, instance, class, client type) the driver walks after &amp;lt;code&amp;gt;GPU_GET_ENGINES&amp;lt;/code&amp;gt;; each must be self-consistent or the driver rewrites the following allocation.&lt;br /&gt;
|-&lt;br /&gt;
| '''GMMU'''&lt;br /&gt;
| GPU Memory Management Unit: page tables, TLB, fault handling.&lt;br /&gt;
|-&lt;br /&gt;
| '''PDB'''&lt;br /&gt;
| Page Directory Base: root of a GPU page table.&lt;br /&gt;
|-&lt;br /&gt;
| '''PDE / PTE'''&lt;br /&gt;
| Page-directory entry / page-table entry.&lt;br /&gt;
|-&lt;br /&gt;
| '''UVM'''&lt;br /&gt;
| NVIDIA's unified memory module: VA spaces, page trees, faults, channel manager ([[UVM in the Guest|&amp;lt;code&amp;gt;UVM-in-the-Guest.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
|-&lt;br /&gt;
| '''VA / PA / GPA / IOVA'''&lt;br /&gt;
| Virtual address / physical address / guest physical address / I/O virtual address.&lt;br /&gt;
|-&lt;br /&gt;
| '''vidmem / sysmem / aperture'''&lt;br /&gt;
| GPU local memory / system memory / how an address is qualified.&lt;br /&gt;
|-&lt;br /&gt;
| '''Semaphore / tracker'''&lt;br /&gt;
| A memory location written by the GPU to signal progress; UVM's tracker waits on it.&lt;br /&gt;
|-&lt;br /&gt;
| '''AMAPlib'''&lt;br /&gt;
| NVIDIA's shared &amp;quot;address mapping&amp;quot; library: swizzling, bank/channel mapping, aperture rules.&lt;br /&gt;
|-&lt;br /&gt;
| '''HAL'''&lt;br /&gt;
| Hardware abstraction layer: per-generation functions that program registers and formats.&lt;br /&gt;
|-&lt;br /&gt;
| '''Class list (classDB)'''&lt;br /&gt;
| The RM classes reported as supported; engine queries are filtered against it, so the class list, engine list and capability controls must agree.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Method and tooling ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Term&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| '''Host oracle / A-B harness'''&lt;br /&gt;
| The same query or deterministic workload run against a bare-metal host driver and inside the guest, then diffed — the reference for what the guest should have seen.&lt;br /&gt;
|-&lt;br /&gt;
| '''File virtual address (&amp;lt;code&amp;gt;libcuda+0x...&amp;lt;/code&amp;gt;)'''&lt;br /&gt;
| An address relative to the start of a shared object file, as distinct from a runtime mapping or a disassembler program address.&lt;br /&gt;
|-&lt;br /&gt;
| '''Session (risc-v-gsp-rm-debugger)'''&lt;br /&gt;
| A recorded run of the firmware workbench — the unit of evidence ([[risc-v-gsp-rm-debugger|&amp;lt;code&amp;gt;Riscv-GSP-RM-Debugger.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Related pages ==&lt;br /&gt;
&lt;br /&gt;
* [[FAQ|&amp;lt;code&amp;gt;FAQ.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[GSP and GSP-RM|&amp;lt;code&amp;gt;GSP-and-GSP-RM.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]]&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=RPC_Message_Format&amp;diff=23953</id>
		<title>RPC Message Format</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=RPC_Message_Format&amp;diff=23953"/>
		<updated>2026-10-12T04:29:51Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= GSP RPC Message Format Specification =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' This page describes the legacy BAR0 mailbox RPC model: the 64-byte &amp;lt;code&amp;gt;GSPR&amp;lt;/code&amp;gt; magic header and the 12-type model below are '''not''' the path the guest driver uses. The live GSP-RM path is a message queue in guest system memory with 4 KB queue elements and a 32-byte RPC header (signature &amp;lt;code&amp;gt;0x43505256&amp;lt;/code&amp;gt;, header version &amp;lt;code&amp;gt;0x03000000&amp;lt;/code&amp;gt;); functions are a flat enum (&amp;lt;code&amp;gt;SET_GUEST_SYSTEM_INFO&amp;lt;/code&amp;gt; 1, &amp;lt;code&amp;gt;FREE&amp;lt;/code&amp;gt; 10, &amp;lt;code&amp;gt;GET_GSP_STATIC_INFO&amp;lt;/code&amp;gt; 65, &amp;lt;code&amp;gt;GSP_RM_CONTROL&amp;lt;/code&amp;gt; 76, &amp;lt;code&amp;gt;GSP_RM_ALLOC&amp;lt;/code&amp;gt; 103, ...). Canonical documentation: [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/03-gsp-and-gsp-rm.md &amp;lt;code&amp;gt;../docs/03-architecture/03-gsp-and-gsp-rm.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The GSP firmware uses a dispatcher-based RPC system with two dispatchers:&lt;br /&gt;
&lt;br /&gt;
* '''Primary''' (0x057A1AC0): ALLOC, FREE, MAP, UNMAP, PIN, UNPIN, SCHEDULE, YIELD, NOTIFY, BAR_TRAP, MIGRATE, DEBUG&lt;br /&gt;
* '''Secondary''' (0x04ED39DC): Branch-based dispatch for all 11 types&lt;br /&gt;
&lt;br /&gt;
== Primary Dispatcher Call Convention ==&lt;br /&gt;
&lt;br /&gt;
=== Entry Point ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FUN_ram_057a1ac0(&lt;br /&gt;
    uint32_t rpc_type,      // param_1: RPC type (0x01-0x0C)&lt;br /&gt;
    uint8_t  flags_a,       // param_2&lt;br /&gt;
    uint8_t  flags_b,       // param_3&lt;br /&gt;
    uint8_t  flags_c,       // param_4&lt;br /&gt;
    uint32_t *out_subcmd_id,// param_5: Returns sub-command ID&lt;br /&gt;
    uint8_t  *out_a,        // param_6: Echoes flags_b&lt;br /&gt;
    uint8_t  *out_b,        // param_7: Echoes flags_a&lt;br /&gt;
    uint8_t  *out_c         // param_8: Echoes flags_c&lt;br /&gt;
) -&amp;amp;gt; int64_t&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== RPC Type to Sub-Command Mapping ===&lt;br /&gt;
&lt;br /&gt;
The primary dispatcher validates RPC type, then indexes into the 32-entry jump table at '''0x057A3AD8'''.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! RPC Type&lt;br /&gt;
! Name&lt;br /&gt;
! Subcmd Range&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x01&lt;br /&gt;
| ALLOC&lt;br /&gt;
| 0-31&lt;br /&gt;
| Uses 0x057E94EC main&lt;br /&gt;
|-&lt;br /&gt;
| 0x02&lt;br /&gt;
| FREE&lt;br /&gt;
| 0-31&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 0x03&lt;br /&gt;
| MAP&lt;br /&gt;
| —&lt;br /&gt;
| Uses secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x04&lt;br /&gt;
| UNMAP&lt;br /&gt;
| 0-31&lt;br /&gt;
| Primary + secondary&lt;br /&gt;
|-&lt;br /&gt;
| 0x05&lt;br /&gt;
| PIN&lt;br /&gt;
| —&lt;br /&gt;
| Uses secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x06&lt;br /&gt;
| UNPIN&lt;br /&gt;
| —&lt;br /&gt;
| Uses secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x07&lt;br /&gt;
| SCHEDULE&lt;br /&gt;
| 0-31&lt;br /&gt;
| Uses 0x051EFBF4 main&lt;br /&gt;
|-&lt;br /&gt;
| 0x08&lt;br /&gt;
| YIELD&lt;br /&gt;
| —&lt;br /&gt;
| Uses secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x09&lt;br /&gt;
| NOTIFY&lt;br /&gt;
| —&lt;br /&gt;
| Uses secondary dispatcher&lt;br /&gt;
|-&lt;br /&gt;
| 0x0A&lt;br /&gt;
| BAR_TRAP&lt;br /&gt;
| —&lt;br /&gt;
| Uses 0x04CB8188&lt;br /&gt;
|-&lt;br /&gt;
| 0x0B&lt;br /&gt;
| MIGRATE&lt;br /&gt;
| 0-15 x2&lt;br /&gt;
| Dual jump tables&lt;br /&gt;
|-&lt;br /&gt;
| 0x0C&lt;br /&gt;
| DEBUG&lt;br /&gt;
| —&lt;br /&gt;
| Unimplemented&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sub-Command Descriptor (Returned by Jump Table Handlers) ===&lt;br /&gt;
&lt;br /&gt;
Each sub-command handler at the jump table returns:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t subcmd_id;     // Constant ID (e.g., 0x10, 0x14, 0x40)&lt;br /&gt;
    uint8_t  echo_flags_b;  // Copy of input flags_b&lt;br /&gt;
    uint8_t  echo_flags_a;  // Copy of input flags_a&lt;br /&gt;
    uint8_t  echo_flags_c;  // Copy of input flags_c&lt;br /&gt;
} __attribute__((packed)) subcmd_descriptor_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Example: Subcmd 3 (0x057A1BCC)'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Returns ID = 0x10&lt;br /&gt;
*out_subcmd_id = 0x10;&lt;br /&gt;
*out_a = flags_b;&lt;br /&gt;
*out_b = flags_a;&lt;br /&gt;
*out_c = flags_c;&lt;br /&gt;
return 0;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Example: Subcmd 0 (0x057A1DB4)'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Returns ID = 0x40&lt;br /&gt;
*out_subcmd_id = 0x40;&lt;br /&gt;
*out_a = flags_b;&lt;br /&gt;
*out_b = flags_a;&lt;br /&gt;
*out_c = flags_c;&lt;br /&gt;
return 0;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Secondary Dispatcher Call Convention ==&lt;br /&gt;
&lt;br /&gt;
=== Entry Point ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FUN_ram_04ed39dc(rpc_message_t *msg) -&amp;amp;gt; int64_t&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message Structure (Inferred) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t rpc_type;      // 0x01-0x0B&lt;br /&gt;
    uint32_t sub_type;      // Sub-operation code&lt;br /&gt;
    uint64_t payload_ptr;   // Pointer to RPC-specific payload&lt;br /&gt;
    uint32_t payload_size;  // Size of payload&lt;br /&gt;
    uint32_t flags;         // Control flags&lt;br /&gt;
    uint64_t context;       // Opaque context&lt;br /&gt;
    uint32_t sequence;      // Sequence number&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} __attribute__((packed)) rpc_message_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Branch-Based Dispatch ===&lt;br /&gt;
&lt;br /&gt;
Secondary dispatcher uses &amp;lt;code&amp;gt;bgeu&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;bltu&amp;lt;/code&amp;gt; branches on &amp;lt;code&amp;gt;rpc_type&amp;lt;/code&amp;gt; register:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# Pseudocode&lt;br /&gt;
if (rpc_type &amp;amp;gt;= 0x0C) goto error;&lt;br /&gt;
switch(rpc_type):&lt;br /&gt;
  case 0x03: call MAP_handler_A;&lt;br /&gt;
  case 0x04: call UNMAP_handler_A;&lt;br /&gt;
  case 0x05: call PIN_handler_A (0x04ED34B8);&lt;br /&gt;
  case 0x06: call UNPIN_handler_A;&lt;br /&gt;
  case 0x07: call SCHEDULE_handler_A;&lt;br /&gt;
  case 0x08: call YIELD_handler_A;&lt;br /&gt;
  case 0x09: call NOTIFY_handler_A;&lt;br /&gt;
  case 0x0A: call BAR_TRAP_handler (0x057675B7);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== RPC-Specific Payloads ==&lt;br /&gt;
&lt;br /&gt;
=== ALLOC (0x01) - Via 0x057E94EC ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint64_t size;          // Allocation size in bytes&lt;br /&gt;
    uint32_t type;          // Memory type (VRAM, sysmem, etc.)&lt;br /&gt;
    uint32_t alignment;     // Alignment requirement&lt;br /&gt;
    uint64_t va_hint;       // Virtual address hint&lt;br /&gt;
    uint32_t flags;         // CACHE_COHERENT, UNCACHED, etc.&lt;br /&gt;
    uint32_t pid;           // Process ID&lt;br /&gt;
    uint32_t vf_id;         // VF ID (for vGPU)&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
    uint64_t *out_handle;   // Output: allocation handle&lt;br /&gt;
    uint64_t *out_va;       // Output: mapped virtual address&lt;br /&gt;
    uint64_t *out_pa;       // Output: physical address&lt;br /&gt;
} alloc_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MAP (0x03) - Handlers 0x05766AB7 / 0x05778A37 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint64_t handle;        // Allocation handle from ALLOC&lt;br /&gt;
    uint64_t va;            // Target virtual address&lt;br /&gt;
    uint64_t size;          // Map size&lt;br /&gt;
    uint32_t prot;          // PROT_READ|PROT_WRITE|PROT_EXEC&lt;br /&gt;
    uint32_t flags;         // MAP_FIXED, MAP_SHARED, etc.&lt;br /&gt;
    uint32_t vf_id;         // Target VF&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} map_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== PIN (0x05) - Handler 0x04ED34B8 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint64_t handle;        // Allocation handle&lt;br /&gt;
    uint64_t offset;        // Offset within allocation&lt;br /&gt;
    uint64_t size;          // Size to pin&lt;br /&gt;
    uint32_t vf_id;         // Target VF&lt;br /&gt;
    uint32_t flags;         // PIN_WRITE, PIN_READ, PIN_LONGTERM&lt;br /&gt;
    uint64_t *out_dma_addr; // Output: DMA address for device&lt;br /&gt;
} pin_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SCHEDULE (0x07) - Via 0x051EFBF4 / 0x05767F37 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t vf_id;         // VF to schedule&lt;br /&gt;
    uint32_t priority;      // Scheduling priority&lt;br /&gt;
    uint64_t time_slice_ns; // Time slice in nanoseconds&lt;br /&gt;
    uint32_t flags;         // PREEMPTIBLE, REALTIME, etc.&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} schedule_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== BAR_TRAP (0x0A) - Handler 0x04CB8188 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t bar_index;     // BAR number (0-5)&lt;br /&gt;
    uint32_t trap_type;     // READ, WRITE, ATOMIC&lt;br /&gt;
    uint64_t offset;        // Offset within BAR&lt;br /&gt;
    uint64_t value;         // Value for writes&lt;br /&gt;
    uint32_t size;          // Access size (1,2,4,8)&lt;br /&gt;
    uint32_t vf_id;         // Trapping VF&lt;br /&gt;
    uint64_t *out_value;    // Output: read value&lt;br /&gt;
} bar_trap_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== MIGRATE (0x0B) - Dual Jump Tables ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t phase;         // 0=prepare, 1=transfer, 2=commit, 3=cleanup&lt;br /&gt;
    uint32_t subcmd;        // Sub-command index (0-15 for each table)&lt;br /&gt;
    uint64_t src_vf;        // Source VF&lt;br /&gt;
    uint64_t dst_vf;        // Destination VF&lt;br /&gt;
    uint64_t data_ptr;      // Migration data buffer&lt;br /&gt;
    uint64_t data_size;     // Buffer size&lt;br /&gt;
    uint32_t flags;         // LIVE, POSTCOPY, etc.&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} migrate_payload_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wire Format (Host → GSP) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Legacy BAR0 mailbox format — not used by the guest driver.''' The current msgq header/element facts are in the note at the top of this page.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Message Header (64 bytes) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t magic;         // 0x47535052 (&amp;quot;GSPR&amp;quot;)&lt;br /&gt;
    uint32_t version;       // Protocol version (1)&lt;br /&gt;
    uint32_t rpc_type;      // 0x01-0x0C&lt;br /&gt;
    uint32_t sequence;      // Monotonic sequence&lt;br /&gt;
    uint64_t timestamp_ns;  // Submission timestamp&lt;br /&gt;
    uint32_t payload_size;  // Size of payload&lt;br /&gt;
    uint32_t flags;         // MSG_SYNC, MSG_ASYNC, MSG_NOREPLY&lt;br /&gt;
    uint64_t correlation_id;// For async matching&lt;br /&gt;
    uint64_t reserved[3];   // Padding to 64 bytes&lt;br /&gt;
} __attribute__((packed)) rpc_header_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Complete Message ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;+------------------+&lt;br /&gt;
| rpc_header_t     |  64 bytes&lt;br /&gt;
+------------------+&lt;br /&gt;
| payload (varies) |  payload_size bytes&lt;br /&gt;
+------------------+&lt;br /&gt;
| padding to 256B  |  (alignment)&lt;br /&gt;
+------------------+&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Response Format ==&lt;br /&gt;
&lt;br /&gt;
=== Synchronous Response ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    int64_t status;         // 0 = success, negative = error&lt;br /&gt;
    uint32_t rpc_type;      // Echo of request&lt;br /&gt;
    uint32_t sequence;      // Echo of request&lt;br /&gt;
    uint64_t timestamp_ns;  // Completion timestamp&lt;br /&gt;
    uint32_t payload_size;  // Response payload size&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} __attribute__((packed)) rpc_response_header_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error Codes ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| OK&lt;br /&gt;
| Success&lt;br /&gt;
|-&lt;br /&gt;
| -1 (0xFFFF)&lt;br /&gt;
| EPERM&lt;br /&gt;
| Permission denied&lt;br /&gt;
|-&lt;br /&gt;
| -2 (0xFFFE)&lt;br /&gt;
| ENOENT&lt;br /&gt;
| Not found&lt;br /&gt;
|-&lt;br /&gt;
| -3 (0xFFFD)&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Invalid argument&lt;br /&gt;
|-&lt;br /&gt;
| -6 (0xFFFA)&lt;br /&gt;
| ENODEV&lt;br /&gt;
| No such device&lt;br /&gt;
|-&lt;br /&gt;
| -12 (0xFFF4)&lt;br /&gt;
| ENOMEM&lt;br /&gt;
| Out of memory&lt;br /&gt;
|-&lt;br /&gt;
| -16 (0xFFEE)&lt;br /&gt;
| EBUSY&lt;br /&gt;
| Resource busy&lt;br /&gt;
|-&lt;br /&gt;
| -22 (0xFFEA)&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Invalid argument&lt;br /&gt;
|-&lt;br /&gt;
| -28 (0xFFE4)&lt;br /&gt;
| ENOSPC&lt;br /&gt;
| No space left&lt;br /&gt;
|-&lt;br /&gt;
| -37 (0xFFDB)&lt;br /&gt;
| ENOLCK&lt;br /&gt;
| No locks available&lt;br /&gt;
|-&lt;br /&gt;
| -56 (0xFFC8)&lt;br /&gt;
| EBADMSG&lt;br /&gt;
| Bad message&lt;br /&gt;
|-&lt;br /&gt;
| -84 (0xFFAC)&lt;br /&gt;
| EOVERFLOW&lt;br /&gt;
| Value too large&lt;br /&gt;
|-&lt;br /&gt;
| -90 (0xFFA6)&lt;br /&gt;
| ENOSTR&lt;br /&gt;
| Not a stream&lt;br /&gt;
|-&lt;br /&gt;
| -91 (0xFFA5)&lt;br /&gt;
| ENODATA&lt;br /&gt;
| No data available&lt;br /&gt;
|-&lt;br /&gt;
| -94 (0xFFA2)&lt;br /&gt;
| ENOSR&lt;br /&gt;
| Out of streams resources&lt;br /&gt;
|-&lt;br /&gt;
| -97 (0xFF9F)&lt;br /&gt;
| EPROTO&lt;br /&gt;
| Protocol error&lt;br /&gt;
|-&lt;br /&gt;
| -111 (0xFF91)&lt;br /&gt;
| ETIMEDOUT&lt;br /&gt;
| Connection timed out&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Kernel Client Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== Message Builder ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;static int gsp_rpc_send(gsp_client_t *client, uint32_t rpc_type, &lt;br /&gt;
                        void *payload, size_t payload_size,&lt;br /&gt;
                        void *response, size_t *response_size) {&lt;br /&gt;
    rpc_header_t hdr = {&lt;br /&gt;
        .magic = 0x47535052,&lt;br /&gt;
        .version = 1,&lt;br /&gt;
        .rpc_type = rpc_type,&lt;br /&gt;
        .sequence = atomic_inc(&amp;amp;amp;client-&amp;amp;gt;seq),&lt;br /&gt;
        .timestamp_ns = ktime_get_ns(),&lt;br /&gt;
        .payload_size = payload_size,&lt;br /&gt;
        .flags = MSG_SYNC,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    // Build complete message&lt;br /&gt;
    uint8_t msg[256];&lt;br /&gt;
    memcpy(msg, &amp;amp;amp;hdr, sizeof(hdr));&lt;br /&gt;
    memcpy(msg + 64, payload, payload_size);&lt;br /&gt;
    &lt;br /&gt;
    // Submit to GSP doorbell&lt;br /&gt;
    return gsp_doorbell_ring(client-&amp;amp;gt;gsp, msg, sizeof(msg));&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Doorbell Mechanism ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// GSP doorbell register (PCIe BAR0 + offset)&lt;br /&gt;
#define GSP_DOORBELL_OFFSET  0x1000&lt;br /&gt;
&lt;br /&gt;
static void gsp_doorbell_ring(gsp_device_t *gsp, void *msg, size_t len) {&lt;br /&gt;
    // Copy message to shared memory ring&lt;br /&gt;
    // Ring GSP doorbell&lt;br /&gt;
    writel(1, gsp-&amp;amp;gt;bar0 + GSP_DOORBELL_OFFSET);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Async Completion ==&lt;br /&gt;
&lt;br /&gt;
=== Notification Mechanism ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t rpc_type;&lt;br /&gt;
    uint32_t sequence;&lt;br /&gt;
    int64_t status;&lt;br /&gt;
    uint64_t timestamp_ns;&lt;br /&gt;
    uint32_t payload_size;&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
} async_completion_t;&lt;br /&gt;
&lt;br /&gt;
// Delivered via MSI-X or GSP notification queue&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
* Primary Dispatcher: 0x057A1AC0&lt;br /&gt;
* Secondary Dispatcher: 0x04ED39DC&lt;br /&gt;
* Jump Table: 0x057A3AD8 (32 entries)&lt;br /&gt;
* RPC Type Jump Table: 0x059BFEB0 (12 types)&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Project_Status&amp;diff=23952</id>
		<title>Project Status</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Project_Status&amp;diff=23952"/>
		<updated>2026-10-12T04:29:51Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Project Status =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' The honest, dated state of the project: what works today, what is in progress, and what is not started. It is refreshed periodically and each claim maps to a maintained document in the repository. Canonical sources: [https://git.vgpu.io/open-iov/blob/master/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;] (project front door), [https://git.vgpu.io/open-iov/blob/master/docs/04-implementation/01-known-knowns-and-unknowns.md &amp;lt;code&amp;gt;../docs/04-implementation/01-known-knowns-and-unknowns.md&amp;lt;/code&amp;gt;] (known-knowns and known-unknowns) and [https://git.vgpu.io/open-iov/blob/master/docs/04-implementation/03-execution-frontier.md &amp;lt;code&amp;gt;../docs/04-implementation/03-execution-frontier.md&amp;lt;/code&amp;gt;] (the execution frontier). When this page and the docs disagree, the docs tree wins.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; proven with the stock guest driver; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented, default-off or behind supervised gates; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partially implemented; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; current blocker; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; named success state; &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; designed, not built.&lt;br /&gt;
&lt;br /&gt;
== 1. Milestone ladder ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Milestone&lt;br /&gt;
! State&lt;br /&gt;
|-&lt;br /&gt;
| Emulated vGPU device (PCI, BARs, MSI-X, VFIO mdev)&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; working&lt;br /&gt;
|-&lt;br /&gt;
| GSP boot emulation (FWSEC / booter / RISCV handshake)&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; working&lt;br /&gt;
|-&lt;br /&gt;
| GSP-RM message queues and RPC transport&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; working&lt;br /&gt;
|-&lt;br /&gt;
| Stock guest driver probe and &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; (TU104)&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; working&lt;br /&gt;
|-&lt;br /&gt;
| CUDA userspace init and the driver-API smoke (&amp;lt;code&amp;gt;cuInit&amp;lt;/code&amp;gt;, device enumeration, &amp;lt;code&amp;gt;cuCtxCreate&amp;lt;/code&amp;gt;, allocation, copies, free, destroy)&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; working — the smoke prints &amp;lt;code&amp;gt;ALL OK&amp;lt;/code&amp;gt; and the 64-byte payload round-trips exactly&lt;br /&gt;
|-&lt;br /&gt;
| Guest CUDA kernel execution on real hardware&lt;br /&gt;
| &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; a forwarded guest launch reaches the engine queue (the front end deposits the methods and the scheduling path accepts them), but the engine does not yet execute the forwarded launch descriptor — an engine-authored release has not been observed. Emulation-mode kernel runs (executed through the host bridge on a no-claim path) have completed green; reproducibility of the green path across boots is an open issue&lt;br /&gt;
|-&lt;br /&gt;
| Physical backend on real hardware (module-owned GPU running its real GSP-RM)&lt;br /&gt;
| &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; boot, RPC session, object creation and copy-engine work proven; GR execution is the same frontier as above&lt;br /&gt;
|-&lt;br /&gt;
| Multi-tenant isolation (mdev per VM, per-context page directories)&lt;br /&gt;
| &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; designed; the baseline service-state ownership work is in progress&lt;br /&gt;
|-&lt;br /&gt;
| OpenGL / Vulkan (3D), video&lt;br /&gt;
| &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Windows guests&lt;br /&gt;
| &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; (target)&lt;br /&gt;
|-&lt;br /&gt;
| Xen / Argo / OpenXT / Qubes Air transports&lt;br /&gt;
| &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; (the emulation core is hypervisor-independent by construction)&lt;br /&gt;
|-&lt;br /&gt;
| Live migration&lt;br /&gt;
| &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Performance numbers&lt;br /&gt;
| &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; — no published numbers yet; any claim will ship with its measurement methodology&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 2. What &amp;quot;CUDA works&amp;quot; means here ==&lt;br /&gt;
&lt;br /&gt;
A green &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; or even a passing driver-API smoke is not &amp;quot;CUDA works&amp;quot;. The project's definition of done for CUDA requires all of the following ([https://git.vgpu.io/open-iov/blob/master/docs/04-implementation/01-known-knowns-and-unknowns.md &amp;lt;code&amp;gt;../docs/04-implementation/01-known-knowns-and-unknowns.md&amp;lt;/code&amp;gt;]):&lt;br /&gt;
&lt;br /&gt;
# Stock guest driver probe, &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt;, device enumeration — done.&lt;br /&gt;
# Context creation and the full driver-API surface (&amp;lt;code&amp;gt;cuMemAlloc&amp;lt;/code&amp;gt;, copies, free, destroy) — done.&lt;br /&gt;
# A guest kernel launch that '''executes on real hardware''' and is proven by an engine-authored completion — the current frontier.&lt;br /&gt;
# Memory the guest's work refers to resolving correctly end to end (the VA↔PA model) — partially, for the paths exercised so far.&lt;br /&gt;
# Correct completion, semaphore and fault semantics back to the guest — CE class work has the relay; GR is open.&lt;br /&gt;
# Reproducibility: every boot, not a lucky one — an open issue.&lt;br /&gt;
# No ad-hoc default-off parameters required for the canonical path.&lt;br /&gt;
&lt;br /&gt;
Until every gate holds, the honest formulation is: '''initialization and the driver-API path work; engine execution is in progress.'''&lt;br /&gt;
&lt;br /&gt;
== 3. How to see it yourself ==&lt;br /&gt;
&lt;br /&gt;
The reference setup takes about half an hour from a fresh host ([[Install and First Run|&amp;lt;code&amp;gt;Install-and-First-Run.md&amp;lt;/code&amp;gt;]]); the current expected outcome is exactly the ladder above — driver probe, &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt;, the full driver-API smoke, and the execution frontier where it stands. The risc-v-gsp-rm-debugger workbench ([[risc-v-gsp-rm-debugger|&amp;lt;code&amp;gt;Riscv-GSP-RM-Debugger.md&amp;lt;/code&amp;gt;]]) is the host-side tooling used to study the firmware side of that frontier.&lt;br /&gt;
&lt;br /&gt;
== 4. How this page is maintained ==&lt;br /&gt;
&lt;br /&gt;
Every claim above carries a date and a tag, maps to a maintained document in the repository, and is refreshed as milestones land. The execution story, with its evidence and its open theories, is on [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
== 5. Related pages ==&lt;br /&gt;
&lt;br /&gt;
* [[Install and First Run|&amp;lt;code&amp;gt;Install-and-First-Run.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
* [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]] — which hardware and software combinations are Reference, Target or Experimental.&lt;br /&gt;
* [[FAQ|&amp;lt;code&amp;gt;FAQ.md&amp;lt;/code&amp;gt;]]&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Physical_GPU_Backend_and_Guest_Wiring&amp;diff=23951</id>
		<title>Physical GPU Backend and Guest Wiring</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Physical_GPU_Backend_and_Guest_Wiring&amp;diff=23951"/>
		<updated>2026-10-12T04:29:50Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Physical GPU Backend and Guest Wiring =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' The design that executes guest work on the real GPU: why the host driver cannot be the path and how the live GSP-RM session is wired to the guest-facing emulation. Canonical sources: [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/08-physical-gpu-integration.md &amp;lt;code&amp;gt;../docs/03-architecture/08-physical-gpu-integration.md&amp;lt;/code&amp;gt;] and [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/11-physical-backend-guest-wiring.md &amp;lt;code&amp;gt;../docs/03-architecture/11-physical-backend-guest-wiring.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; proven with the stock guest driver; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented default-off; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; partially built; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; current blocker; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; planned end state.&lt;br /&gt;
&lt;br /&gt;
== 1. The problem and its constraints ==&lt;br /&gt;
&lt;br /&gt;
The guest's real work (copies, memory operations, grid launches) must execute on the physical GPU. The constraints: one DKMS kernel module on the host, no daemon and no new host userspace; host and guest drivers unmodified, with no paravirtual enlightenment in the guest; all emulation and translation logic inside the module; and real execution — compute is not emulated in software.&lt;br /&gt;
&lt;br /&gt;
== 2. Why the host driver is not the path ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Interface&lt;br /&gt;
! What it offers&lt;br /&gt;
! Reachable from our module?&lt;br /&gt;
|-&lt;br /&gt;
| Host driver (distribution build)&lt;br /&gt;
| resource management, scheduling, memory&lt;br /&gt;
| No — no general RM entry points for third-party modules, no kernel-client interface, user-pointer ioctl surface&lt;br /&gt;
|-&lt;br /&gt;
| Host driver peer-memory exports&lt;br /&gt;
| pin/map memory for peer devices&lt;br /&gt;
| Partially — memory only, no submission&lt;br /&gt;
|-&lt;br /&gt;
| Vendor vGPU host stack&lt;br /&gt;
| mediated work submission and scheduling&lt;br /&gt;
| Requires the licensed vGPU host branch and a vGPU-aware guest — excluded&lt;br /&gt;
|-&lt;br /&gt;
| SR-IOV virtual functions&lt;br /&gt;
| hardware-partitioned device&lt;br /&gt;
| Not available on this GPU generation&lt;br /&gt;
|-&lt;br /&gt;
| The GPU's own GSP firmware&lt;br /&gt;
| the resource manager server itself&lt;br /&gt;
| Yes — once the module owns the device; this is the path used&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
With an unmodified host driver there is no callable submission interface into it, so the module must own the device and talk to the hardware itself.&lt;br /&gt;
&lt;br /&gt;
== 3. Mechanism options and the decision ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; (A) Proxy through the host driver: module -&amp;amp;gt; host driver's RM -&amp;amp;gt; real channel&lt;br /&gt;
     -&amp;amp;gt; GPU. Needs a modified host driver or a vendor interface — not implementable.&lt;br /&gt;
 (B) Own the GPU; own scheduling (no GSP): module -&amp;amp;gt; own channels/runlists/page&lt;br /&gt;
     tables -&amp;amp;gt; GPU. Reproduces the scheduler, MMU ownership, context switching.&lt;br /&gt;
 (C) Hybrid — only meaningful once (A) and (B) exist; not on the critical path.&lt;br /&gt;
 (D) Own the GPU; use its real GSP firmware as the server      &amp;amp;lt;- chosen&lt;br /&gt;
     guest push -&amp;amp;gt; module -&amp;amp;gt; real GSP-RM session -&amp;amp;gt; real channel -&amp;amp;gt; GPU&lt;br /&gt;
     The module becomes the host-side resource-manager client; scheduling,&lt;br /&gt;
     page tables and context management stay the firmware's job.&lt;br /&gt;
 (E) Vendor-managed sharing (vGPU host stack, SR-IOV VFs) — deployment-gated; out of scope.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Option (D) is the recorded decision (2026-09-29): the only option satisfying module-only, no-daemon, unmodified drivers, real execution, and multi-tenant sharing.&lt;br /&gt;
&lt;br /&gt;
== 4. The chosen mechanism: bring-up ladder ==&lt;br /&gt;
&lt;br /&gt;
The module binds the physical GPU as its driver while the distribution driver is unbound (dedicated-GPU deployment, §9). Each stage is reversible and independently verified:&lt;br /&gt;
&lt;br /&gt;
# '''Ownership''' — the board's power domain is held active across the window (the platform, not PCI, owns it); the module binds the device and maps BAR0/1/3. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Firmware staging''' — the matching GSP image is fetched and validated (ELF64 RISC-V; loadable section, version, hardware signature); no device state touched. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Boot''' — protected region in video memory, secure-verification stage, booter, RISC-V core start: FWSEC → Booter Load → RISC-V active → GSP-RM init-done. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Host RM client''' — the module speaks the already-mapped RPC protocol to the real firmware: device/subdevice, vaspaces, channels, memory. &amp;quot;Call the host driver's RM&amp;quot; becomes &amp;quot;be the RM client&amp;quot;. &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Guest mediation''' — the guest-facing emulation stays unchanged; real-resource objects translate to GSP-RM requests, and server-owned ranges populate the real MMU. &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Work path''' — decoded guest pushes become real push streams; resolved host pages map through module-built scratch page tables; the firmware schedules the work. &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt;&lt;br /&gt;
# '''Completion relay''' — hardware-completed semaphores land in guest-polled memory; events and faults relay through the existing MSI-X injection path. &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 5. The two planes and the wiring ==&lt;br /&gt;
&lt;br /&gt;
The '''emulation plane''' serves the guest: BAR shadows, the sysmem msgq protocol, a hand-built TU104 static-configuration model, and a software work pipeline that executes decoded memsets, copies and semaphore releases. The '''physical backend plane''' owns the device, boots the real GSP-RM and runs the RM client ladder. The wiring joins them at the lifecycle seam (mdev create/remove), a static-config identity overlay, a read-only control whitelist, and — for eligible copy-engine work — the scratch-mapped forwarding path, all default-off and fail-open to software.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GUEST (QEMU)    HOST: vgsp.ko (module-owned GPU)                  PHYSICAL GPU&lt;br /&gt;
-----------------------------------------------------------------------------&lt;br /&gt;
INIT  preflight: distribution driver green; no vgsp/mdev/QEMU          [live]&lt;br /&gt;
      claim: power domain held -&amp;amp;gt; distribution driver released -&amp;amp;gt; module&lt;br /&gt;
         binds the device -&amp;amp;gt; liveness check                             [live]&lt;br /&gt;
      boot: FWSEC -&amp;amp;gt; Booter Load -&amp;amp;gt; RISC-V active -&amp;amp;gt; GSP-RM init        [live]&lt;br /&gt;
      mdev + ladder: backend joins the live session; real objects,&lt;br /&gt;
         channels, first real CE copy                                   [live]&lt;br /&gt;
      guest: nvidia.ko probes; emulation serves handshake, static config,&lt;br /&gt;
         RM battery, UVM registration                                   [live]&lt;br /&gt;
WORK  guest CUDA app -&amp;amp;gt; libcuda -&amp;amp;gt; nvidia.ko -&amp;amp;gt; GPFIFO -&amp;amp;gt; doorbell&lt;br /&gt;
      host pump decodes; eligible CE copies forwarded via module-built scratch&lt;br /&gt;
         page tables; GR: launch reaches the front-end, descriptor not seen [wall]&lt;br /&gt;
DONE  engine authors the release in guest memory; host relays via MSI-X   [gated]&lt;br /&gt;
TEARDOWN mdev remove -&amp;amp;gt; QEMU stop -&amp;amp;gt; module unload -&amp;amp;gt; clean GSP-RM shutdown&lt;br /&gt;
      -&amp;amp;gt; protected region down -&amp;amp;gt; distribution driver rebound            [live]&lt;br /&gt;
FAIL  a failed mutating operation parks the device in a locked fail-safe;&lt;br /&gt;
      never auto-retried; recovery is supervised                          [live]&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Proven capabilities ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Capability&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| Control plane (GSP boot emulation, RPC, BAR/PCI/MSI-X)&lt;br /&gt;
| done &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Driver-API baseline (init, devices, context, allocation, copies, free, destroy)&lt;br /&gt;
| done — 64/64 payload round-trip &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Software bridge for decoded memory/state operations&lt;br /&gt;
| in progress &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Device ownership, firmware staging, board-liveness checks&lt;br /&gt;
| verified live &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Power domain held active across the ownership window&lt;br /&gt;
| verified across supervised cycles &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Real GSP boot by the module, through init-done and clean release&lt;br /&gt;
| done, no reboot on clean cycles &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Host RM client and first real engine work (static config, real objects, 4 KiB CE copy)&lt;br /&gt;
| done &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Guest-copy forwarding, deferred release, hardware-primary copies, engine-authored relay, fault relay&lt;br /&gt;
| default-off, verified live; one relayed-copy mismatch under triage &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| CUDA kernel execution (&amp;lt;code&amp;gt;vectorAdd&amp;lt;/code&amp;gt;)&lt;br /&gt;
| open &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; — the launch-descriptor install path; correct results are the &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 7. The execution frontier ==&lt;br /&gt;
&lt;br /&gt;
The RM client ladder reaches the compute engine (a GR0 channel plus a compute-class object). A forwarded guest CUDA launch now reaches the front-end (ring entry fetched, methods executed) but the inline launch-descriptor install has not been observed and no grid has dispatched; context validity at dispatch is ruled out. The wall is the form of the forwarded launch method stream — see [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]. A failed mutating operation on the backend parks the device in a locked fail-safe that is never auto-retried; recovery is a supervised step.&lt;br /&gt;
&lt;br /&gt;
== 8. Safety and platform discipline ==&lt;br /&gt;
&lt;br /&gt;
* '''Dedicated GPU deployment.''' One GPU serves the vGPU service; the host uses another GPU or integrated graphics. The distribution driver stays unmodified and is unbound from that device only while the service is active.&lt;br /&gt;
* '''The board's power domain belongs to the platform.''' Releasing the last driver can power-gate the board and the power-on sequence can fail; the ownership path holds the whole board in a held-active state across the window, verifies config-space liveness, and aborts on any power-loss signature without retry.&lt;br /&gt;
* '''Supervised cycles.''' The device is driven by the module under supervised cycles with a written recovery plan. A failed mutating operation parks the device in a locked fail-safe and is never auto-retried; any reboot requires explicit human approval with a written reason and post-reboot plan first.&lt;br /&gt;
* '''Fail closed.''' No forwarding seam programs guest-derived page tables into the real MMU until the population path is proven end to end; the current forwarded path submits engine work only through module-built scratch page tables mapping already-resolved host pages.&lt;br /&gt;
&lt;br /&gt;
== 9. Sharing policy and isolation ==&lt;br /&gt;
&lt;br /&gt;
* '''Dedicated GPU (chosen):''' one GPU serves the vGPU service; a multi-GPU host gives the distribution driver its own GPU.&lt;br /&gt;
* '''Shared single GPU with the host driver bound:''' no conforming mechanism exists on this generation without vendor interfaces; it would require relaxing a constraint (vendor vGPU stack, SR-IOV hardware, or a host daemon).&lt;br /&gt;
* Isolation is one real GSP client per mdev with per-client page tables; host access to guest memory stays behind the hypervisor's per-device DMA interface, and tenant policy is a later layer on top ([[GMMU Multi-Tenant Protection|&amp;lt;code&amp;gt;GMMU-Multi-Tenant-Protection.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 10. Open questions ==&lt;br /&gt;
&lt;br /&gt;
* Firmware/host driver ABI match for the supported family on the development GPU.&lt;br /&gt;
* GPU unbind/reset lifecycle and recovery after guest faults.&lt;br /&gt;
* Which guest allocations need real VRAM and which can stay in system memory.&lt;br /&gt;
* Fault semantics and per-tenant scheduling once multiple mdevs share the service GPU.&lt;br /&gt;
&lt;br /&gt;
== 11. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/08-physical-gpu-integration.md &amp;lt;code&amp;gt;../docs/03-architecture/08-physical-gpu-integration.md&amp;lt;/code&amp;gt;] — canonical: mechanism choice and device bring-up.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/11-physical-backend-guest-wiring.md &amp;lt;code&amp;gt;../docs/03-architecture/11-physical-backend-guest-wiring.md&amp;lt;/code&amp;gt;] — canonical: the guest-wiring design.&lt;br /&gt;
* [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]], [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]] — the GR wall and the software execution plane.&lt;br /&gt;
* [[The Host Module (vgsp.ko)|&amp;lt;code&amp;gt;Host-Module.md&amp;lt;/code&amp;gt;]] — the module that owns both planes.&lt;br /&gt;
* [[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]] — page-table seams and scratch mappings.&lt;br /&gt;
* [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]], [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] — support scope and the honest status picture.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Migration_Protocol&amp;diff=23950</id>
		<title>Migration Protocol</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Migration_Protocol&amp;diff=23950"/>
		<updated>2026-10-12T04:29:50Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Migration Protocol (RPC 0x0B) =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Historical document — superseded.''' This page records the MIGRATE RPC (type 0x0B) as seen in firmware analysis; in emulation mode the MIGRATE RPC returns &amp;lt;code&amp;gt;-ENOTSUPP&amp;lt;/code&amp;gt;. The live migration implementation is [https://git.vgpu.io/open-iov/blob/master/kernel/migration.c &amp;lt;code&amp;gt;../kernel/migration.c&amp;lt;/code&amp;gt;]; design and status are documented in [https://git.vgpu.io/open-iov/blob/master/docs/04-implementation &amp;lt;code&amp;gt;../docs/04-implementation/&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The MIGRATE RPC (type 0x0B) implements live migration for vGPU virtual functions. It uses '''dual jump tables''' for two-phase migration operations, accessed via the primary dispatcher at 0x057A1AC0.&lt;br /&gt;
&lt;br /&gt;
== Key Addresses ==&lt;br /&gt;
&lt;br /&gt;
=== Migration Jump Tables ===&lt;br /&gt;
&lt;br /&gt;
==== Table 1: 0x04179ED8 (Primary MIGRATE branch at 0x057A1BDC) ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Index&lt;br /&gt;
! Target&lt;br /&gt;
! Decompiled&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x057A2344&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare - returns ID 0x14, checks flag at +0x7F9&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| 0x057A2320&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| 0x057A230C&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 0x057A22F8&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare - returns ID 0x10&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 0x057A2388&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 0x057A23D8&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 0x057A23AC&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| 0x057A2478&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| 0x057A2428&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| 0x057A2454&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| 0x057A2404&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| 0x057A2364&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 1: Prepare variant&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
| Duplicate entry&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| 0x057A299C&lt;br /&gt;
| —&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
| Duplicate entry&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| 0x057A1F3C&lt;br /&gt;
| (dup)&lt;br /&gt;
| Duplicate entry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Table 2: 0x04179FBC (Primary MIGRATE branch at 0x057A1D5C) ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Index&lt;br /&gt;
! Target&lt;br /&gt;
! Decompiled&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| 0x057A257C&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| 0x057A25E4&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| 0x057A24EC&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 0x057A2608&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 0x057A2534&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 0x057A25C0&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 0x057A24A4&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| 0x057A259C&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| 0x057A2510&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| 0x057A2558&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| 0x057A24C8&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| 0x057A262C&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 2: Transfer&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| 0x057A345C&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 3: Commit&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| 0x057A36D8&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 3: Commit&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| 0x057A35D8&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 3: Commit&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| 0x057A3658&lt;br /&gt;
| ✅&lt;br /&gt;
| Phase 3: Commit&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Migration Phases ==&lt;br /&gt;
&lt;br /&gt;
=== Phase 0: Discovery (Pre-migration) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Query VF migratability&lt;br /&gt;
int gsp_migrate_query(struct gsp_vf *vf, struct migrate_query *out) {&lt;br /&gt;
    migrate_payload_t payload = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_QUERY,&lt;br /&gt;
        .subcmd = 0,&lt;br /&gt;
        .src_vf = vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = 0,&lt;br /&gt;
    };&lt;br /&gt;
    return gsp_rpc_send(vf-&amp;amp;gt;gsp, RPC_MIGRATE, &amp;amp;amp;payload, sizeof(payload), out, sizeof(*out));&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Phase 1: Prepare (Table 1, indices 0-11) ===&lt;br /&gt;
&lt;br /&gt;
'''Goal''': Quiesce VF, prepare memory state for transfer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Subcmd 3 (0x057A22F8) - Returns ID 0x10&lt;br /&gt;
int migrate_prepare_quiesce(vf_id) {&lt;br /&gt;
    // 1. Pause VF scheduling&lt;br /&gt;
    // 2. Flush pending commands&lt;br /&gt;
    // 3. Pin all VF memory&lt;br /&gt;
    // 4. Return quiesce token&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Subcmd 0 (0x057A2344) - Returns ID 0x14, checks flag at in_t1+0x7F9&lt;br /&gt;
int migrate_prepare_snapshot(vf_id, *token) {&lt;br /&gt;
    // 1. Snapshot VF register state&lt;br /&gt;
    // 2. Snapshot BAR configurations&lt;br /&gt;
    // 3. Snapshot WPR regions&lt;br /&gt;
    // 4. Snapshot page tables&lt;br /&gt;
    // 5. Return snapshot handle&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Phase 2: Transfer (Table 1 index 13, Table 2 indices 0-11) ===&lt;br /&gt;
&lt;br /&gt;
'''Goal''': Transfer memory pages to destination&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Table 2, subcmd 0 (0x057A257C)&lt;br /&gt;
int migrate_transfer_pages(vf_id, page_list, *progress) {&lt;br /&gt;
    // 1. Iterate page list&lt;br /&gt;
    // 2. For each page:&lt;br /&gt;
    //    a. Copy via DMA (0x0588F9C4)&lt;br /&gt;
    //    b. Verify checksum&lt;br /&gt;
    //    c. Mark page dirty if modified&lt;br /&gt;
    // 3. Return bytes transferred&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Table 2, subcmd 11 (0x057A262C) - Dirty page tracking&lt;br /&gt;
int migrate_track_dirty(vf_id, *dirty_bitmap) {&lt;br /&gt;
    // Return bitmap of pages dirtied since last transfer&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Phase 3: Commit (Table 2 indices 12-15) ===&lt;br /&gt;
&lt;br /&gt;
'''Goal''': Final synchronization, cutover to destination&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Subcmd 12 (0x057A345C)&lt;br /&gt;
int migrate_commit_finalize(vf_id, dst_vf_id) {&lt;br /&gt;
    // 1. Final dirty page transfer&lt;br /&gt;
    // 2. Transfer register state&lt;br /&gt;
    // 3. Activate destination VF&lt;br /&gt;
    // 4. Release source VF resources&lt;br /&gt;
    // 5. Notify completion&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Subcmd 13 (0x057A36D8)&lt;br /&gt;
int migrate_commit_verify(vf_id, *verify_result) {&lt;br /&gt;
    // 1. Verify memory integrity&lt;br /&gt;
    // 2. Verify register state&lt;br /&gt;
    // 3. Verify device state&lt;br /&gt;
    // 4. Return PASS/FAIL&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Phase 4: Cleanup (Post-migration) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int migrate_cleanup(src_vf_id) {&lt;br /&gt;
    // 1. Release pinned memory&lt;br /&gt;
    // 2. Free snapshot buffers&lt;br /&gt;
    // 3. Remove WPR regions&lt;br /&gt;
    // 4. Destroy migration context&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Migration Message Format ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t phase;         // MIGRATE_PHASE_*&lt;br /&gt;
    uint32_t subcmd;        // Sub-command index (0-15 per table)&lt;br /&gt;
    uint64_t src_vf;        // Source VF ID&lt;br /&gt;
    uint64_t dst_vf;        // Destination VF ID&lt;br /&gt;
    uint64_t data_ptr;      // Data buffer (page list, bitmap, etc.)&lt;br /&gt;
    uint64_t data_size;     // Buffer size&lt;br /&gt;
    uint32_t flags;         // MIGRATE_LIVE, MIGRATE_POSTCOPY, etc.&lt;br /&gt;
    uint32_t reserved;&lt;br /&gt;
    uint64_t token;         // Opaque migration token&lt;br /&gt;
} __attribute__((packed)) migrate_payload_t;&lt;br /&gt;
&lt;br /&gt;
#define MIGRATE_PHASE_QUERY     0&lt;br /&gt;
#define MIGRATE_PHASE_PREPARE   1&lt;br /&gt;
#define MIGRATE_PHASE_TRANSFER  2&lt;br /&gt;
#define MIGRATE_PHASE_COMMIT    3&lt;br /&gt;
#define MIGRATE_PHASE_CLEANUP   4&lt;br /&gt;
&lt;br /&gt;
#define MIGRATE_FLAG_LIVE       (1&amp;amp;lt;&amp;amp;lt;0)    // Live migration&lt;br /&gt;
#define MIGRATE_FLAG_POSTCOPY   (1&amp;amp;lt;&amp;amp;lt;1)    // Post-copy mode&lt;br /&gt;
#define MIGRATE_FLAG_AUTO_COMMIT (1&amp;amp;lt;&amp;amp;lt;2)  // Auto-commit after transfer&lt;br /&gt;
#define MIGRATE_FLAG_VERIFY     (1&amp;amp;lt;&amp;amp;lt;3)    // Verify integrity&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sub-Command Descriptors (Returned by Handlers) ==&lt;br /&gt;
&lt;br /&gt;
All migration handlers follow the primary dispatcher pattern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct {&lt;br /&gt;
    uint32_t subcmd_id;     // Constant: 0x10, 0x14, etc.&lt;br /&gt;
    uint8_t  echo_flags_b;  // Copy of input flags_b&lt;br /&gt;
    uint8_t  echo_flags_a;  // Copy of input flags_a&lt;br /&gt;
    uint8_t  echo_flags_c;  // Copy of input flags_c&lt;br /&gt;
} migrate_descriptor_t;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Known Subcmd IDs''':&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Subcmd&lt;br /&gt;
! ID&lt;br /&gt;
! Phase&lt;br /&gt;
|-&lt;br /&gt;
| 0x057A22F8 (Table1[3])&lt;br /&gt;
| 0x10&lt;br /&gt;
| Prepare&lt;br /&gt;
|-&lt;br /&gt;
| 0x057A2344 (Table1[0])&lt;br /&gt;
| 0x14&lt;br /&gt;
| Prepare&lt;br /&gt;
|-&lt;br /&gt;
| Others&lt;br /&gt;
| TBD&lt;br /&gt;
| Transfer/Commit&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== vGPU-IO Integration ==&lt;br /&gt;
&lt;br /&gt;
=== Migration State Machine ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef enum {&lt;br /&gt;
    MIG_STATE_IDLE = 0,&lt;br /&gt;
    MIG_STATE_QUERY,&lt;br /&gt;
    MIG_STATE_PREPARE,&lt;br /&gt;
    MIG_STATE_TRANSFER,&lt;br /&gt;
    MIG_STATE_COMMIT,&lt;br /&gt;
    MIG_STATE_CLEANUP,&lt;br /&gt;
    MIG_STATE_FAILED,&lt;br /&gt;
    MIG_STATE_COMPLETED&lt;br /&gt;
} mig_state_t;&lt;br /&gt;
&lt;br /&gt;
struct gsp_migration {&lt;br /&gt;
    struct gsp_vf *vf;&lt;br /&gt;
    mig_state_t state;&lt;br /&gt;
    uint64_t token;&lt;br /&gt;
    uint64_t dst_vf;&lt;br /&gt;
    struct migrate_progress progress;&lt;br /&gt;
    struct completion comp;&lt;br /&gt;
    struct mutex lock;&lt;br /&gt;
};&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Migration Coordinator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_migration_start(struct gsp_vf *vf, uint64_t dst_vf) {&lt;br /&gt;
    struct gsp_migration *mig = kzalloc(sizeof(*mig), GFP_KERNEL);&lt;br /&gt;
    vf-&amp;amp;gt;migration = mig;&lt;br /&gt;
    mig-&amp;amp;gt;vf = vf;&lt;br /&gt;
    mig-&amp;amp;gt;dst_vf = dst_vf;&lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_QUERY;&lt;br /&gt;
    &lt;br /&gt;
    // Phase 0: Query&lt;br /&gt;
    struct migrate_query qry;&lt;br /&gt;
    gsp_migrate_query(vf, &amp;amp;amp;qry);&lt;br /&gt;
    if (!qry.migratable) return -EINVAL;&lt;br /&gt;
    &lt;br /&gt;
    // Phase 1: Prepare&lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_PREPARE;&lt;br /&gt;
    migrate_payload_t prep = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_PREPARE,&lt;br /&gt;
        .subcmd = 3,  // Quiesce&lt;br /&gt;
        .src_vf = vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = dst_vf,&lt;br /&gt;
    };&lt;br /&gt;
    migrate_descriptor_t desc;&lt;br /&gt;
    gsp_rpc_send(vf-&amp;amp;gt;gsp, RPC_MIGRATE, &amp;amp;amp;prep, sizeof(prep), &amp;amp;amp;desc, sizeof(desc));&lt;br /&gt;
    mig-&amp;amp;gt;token = desc.subcmd_id;  // Use returned token&lt;br /&gt;
    &lt;br /&gt;
    // Phase 2: Transfer (iterative)&lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_TRANSFER;&lt;br /&gt;
    while (!gsp_migration_transfer_iter(mig)) {&lt;br /&gt;
        msleep(10);  // Throttle&lt;br /&gt;
        if (signal_pending(current)) break;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Phase 3: Commit&lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_COMMIT;&lt;br /&gt;
    migrate_payload_t commit = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_COMMIT,&lt;br /&gt;
        .subcmd = 12,&lt;br /&gt;
        .src_vf = vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = dst_vf,&lt;br /&gt;
        .token = mig-&amp;amp;gt;token,&lt;br /&gt;
        .flags = MIGRATE_FLAG_VERIFY,&lt;br /&gt;
    };&lt;br /&gt;
    gsp_rpc_send(vf-&amp;amp;gt;gsp, RPC_MIGRATE, &amp;amp;amp;commit, sizeof(commit), NULL, 0);&lt;br /&gt;
    &lt;br /&gt;
    // Phase 4: Cleanup&lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_CLEANUP;&lt;br /&gt;
    gsp_migration_cleanup(mig);&lt;br /&gt;
    &lt;br /&gt;
    mig-&amp;amp;gt;state = MIG_STATE_COMPLETED;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Transfer Iteration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;bool gsp_migration_transfer_iter(struct gsp_migration *mig) {&lt;br /&gt;
    migrate_payload_t xfer = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_TRANSFER,&lt;br /&gt;
        .subcmd = 0,&lt;br /&gt;
        .src_vf = mig-&amp;amp;gt;vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = mig-&amp;amp;gt;dst_vf,&lt;br /&gt;
        .data_ptr = (uint64_t)mig-&amp;amp;gt;progress.page_list,&lt;br /&gt;
        .data_size = mig-&amp;amp;gt;progress.page_count * sizeof(uint64_t),&lt;br /&gt;
        .token = mig-&amp;amp;gt;token,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    struct migrate_progress prog;&lt;br /&gt;
    int ret = gsp_rpc_send(mig-&amp;amp;gt;vf-&amp;amp;gt;gsp, RPC_MIGRATE, &lt;br /&gt;
                           &amp;amp;amp;xfer, sizeof(xfer), &amp;amp;amp;prog, sizeof(prog));&lt;br /&gt;
    &lt;br /&gt;
    if (ret) return true;  // Error = done&lt;br /&gt;
    &lt;br /&gt;
    mig-&amp;amp;gt;progress.bytes_transferred += prog.bytes_transferred;&lt;br /&gt;
    mig-&amp;amp;gt;progress.pages_transferred += prog.pages_transferred;&lt;br /&gt;
    mig-&amp;amp;gt;progress.dirty_pages = prog.dirty_pages;&lt;br /&gt;
    &lt;br /&gt;
    // Check if more dirty pages to transfer&lt;br /&gt;
    if (prog.dirty_pages &amp;amp;gt; 0 &amp;amp;amp;&amp;amp;amp; !(mig-&amp;amp;gt;flags &amp;amp;amp; MIGRATE_FLAG_POSTCOPY)) {&lt;br /&gt;
        return false;  // Continue iterating&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    return true;  // Transfer complete&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Post-Copy Mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_migration_postcopy(struct gsp_migration *mig) {&lt;br /&gt;
    // Enable post-copy on destination&lt;br /&gt;
    migrate_payload_t pc = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_TRANSFER,&lt;br /&gt;
        .subcmd = 11,  // Dirty tracking&lt;br /&gt;
        .src_vf = mig-&amp;amp;gt;vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = mig-&amp;amp;gt;dst_vf,&lt;br /&gt;
        .flags = MIGRATE_FLAG_POSTCOPY,&lt;br /&gt;
        .token = mig-&amp;amp;gt;token,&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    // Page fault handler on destination&lt;br /&gt;
    gsp_page_fault_handler = gsp_migration_page_fault;&lt;br /&gt;
    &lt;br /&gt;
    return gsp_rpc_send(mig-&amp;amp;gt;vf-&amp;amp;gt;gsp, RPC_MIGRATE, &amp;amp;amp;pc, sizeof(pc), NULL, 0);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Integration with BAR/WPR ==&lt;br /&gt;
&lt;br /&gt;
=== BAR State Migration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_migration_bar_save(struct gsp_migration *mig) {&lt;br /&gt;
    // Save BAR1 aperture, force access state&lt;br /&gt;
    struct bar_save_msg bar_save = {&lt;br /&gt;
        .vf_id = mig-&amp;amp;gt;vf-&amp;amp;gt;id,&lt;br /&gt;
        .bar = 1,&lt;br /&gt;
    };&lt;br /&gt;
    return gsp_rpc_send(mig-&amp;amp;gt;vf-&amp;amp;gt;gsp, RPC_BAR_TRAP,&lt;br /&gt;
                        BAR_SUBCMD_SAVE, &amp;amp;amp;bar_save, sizeof(bar_save),&lt;br /&gt;
                        mig-&amp;amp;gt;bar_state_buf, &amp;amp;amp;mig-&amp;amp;gt;bar_state_size);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int gsp_migration_bar_restore(struct gsp_migration *mig) {&lt;br /&gt;
    // Restore BAR1 on destination&lt;br /&gt;
    struct bar_restore_msg bar_restore = {&lt;br /&gt;
        .vf_id = mig-&amp;amp;gt;dst_vf,&lt;br /&gt;
        .bar = 1,&lt;br /&gt;
        .data = mig-&amp;amp;gt;bar_state_buf,&lt;br /&gt;
        .data_size = mig-&amp;amp;gt;bar_state_size,&lt;br /&gt;
    };&lt;br /&gt;
    return gsp_rpc_send(mig-&amp;amp;gt;vf-&amp;amp;gt;gsp, RPC_BAR_TRAP,&lt;br /&gt;
                        BAR_SUBCMD_RESTORE, &amp;amp;amp;bar_restore, sizeof(bar_restore));&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WPR Region Migration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;int gsp_migration_wpr_save(struct gsp_migration *mig) {&lt;br /&gt;
    // Save WPR regions for VF&lt;br /&gt;
    migrate_payload_t wpr = {&lt;br /&gt;
        .phase = MIGRATE_PHASE_PREPARE,&lt;br /&gt;
        .subcmd = 4,  // WPR snapshot&lt;br /&gt;
        .src_vf = mig-&amp;amp;gt;vf-&amp;amp;gt;id,&lt;br /&gt;
        .dst_vf = mig-&amp;amp;gt;dst_vf,&lt;br /&gt;
        .token = mig-&amp;amp;gt;token,&lt;br /&gt;
    };&lt;br /&gt;
    return gsp_rpc_send(mig-&amp;amp;gt;vf-&amp;amp;gt;gsp, RPC_MIGRATE, &amp;amp;amp;wpr, sizeof(wpr), NULL, 0);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Error Handling ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Phase&lt;br /&gt;
! Error&lt;br /&gt;
! Recovery&lt;br /&gt;
|-&lt;br /&gt;
| Prepare&lt;br /&gt;
| EBUSY&lt;br /&gt;
| Wait, retry&lt;br /&gt;
|-&lt;br /&gt;
| Prepare&lt;br /&gt;
| ENOMEM&lt;br /&gt;
| Reduce snapshot size&lt;br /&gt;
|-&lt;br /&gt;
| Transfer&lt;br /&gt;
| ETIMEDOUT&lt;br /&gt;
| Checkpoint, retry&lt;br /&gt;
|-&lt;br /&gt;
| Transfer&lt;br /&gt;
| EIO&lt;br /&gt;
| Failover to post-copy&lt;br /&gt;
|-&lt;br /&gt;
| Commit&lt;br /&gt;
| EINVAL&lt;br /&gt;
| Rollback to source&lt;br /&gt;
|-&lt;br /&gt;
| Commit&lt;br /&gt;
| ENOSPC&lt;br /&gt;
| Expand destination&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
&lt;br /&gt;
=== Migration Trace Points ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;trace_gsp_mig_phase(vf_id, phase, subcmd, token);&lt;br /&gt;
trace_gsp_mig_transfer(vf_id, pages, bytes, dirty);&lt;br /&gt;
trace_gsp_mig_commit(vf_id, status, verify);&lt;br /&gt;
trace_gsp_mig_error(vf_id, phase, error);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GSP Log Strings ===&lt;br /&gt;
&lt;br /&gt;
Search for migration-related strings in firmware:&lt;br /&gt;
&lt;br /&gt;
* Migration phase markers&lt;br /&gt;
* Page transfer progress&lt;br /&gt;
* Commit verification results&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
* Primary Dispatcher MIGRATE branches: 0x057A1BDC, 0x057A1D54&lt;br /&gt;
* Jump Table 1: 0x04179ED8 (16 entries)&lt;br /&gt;
* Jump Table 2: 0x04179FBC (16 entries)&lt;br /&gt;
* Decompiled handlers: 28 functions in decompiled/&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Introduction_to_GMMU&amp;diff=23949</id>
		<title>Introduction to GMMU</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Introduction_to_GMMU&amp;diff=23949"/>
		<updated>2026-10-12T04:29:49Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Introduction to the GMMU =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' A from-first-principles introduction to the GPU Memory Management Unit (GMMU): what it translates, how its page tables work on our Turing reference, how the host module uses them, and how the GMMU relates to the CPU MMU and the platform IOMMU/SMMU. The architecture chapter is [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/05-gmmu-amap-hal-gr.md &amp;lt;code&amp;gt;../docs/03-architecture/05-gmmu-amap-hal-gr.md&amp;lt;/code&amp;gt;]; the isolation policy authority is [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/14-multi-tenant-gmmu-protection.md &amp;lt;code&amp;gt;../docs/03-architecture/14-multi-tenant-gmmu-protection.md&amp;lt;/code&amp;gt;] (condensed in [[GMMU Multi-Tenant Protection|&amp;lt;code&amp;gt;GMMU-Multi-Tenant-Protection.md&amp;lt;/code&amp;gt;]]).&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Evidence discipline.''' Hardware-format claims condense the tracked field catalogue [https://git.vgpu.io/open-iov/blob/master/debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md &amp;lt;code&amp;gt;../debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md&amp;lt;/code&amp;gt;] and live observations; numeric IDs, layouts and code anchors are cited, and no timing/cycle claim is made.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Status: 2026-10-11, tree &amp;lt;code&amp;gt;master @ 08f39c2f&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed with the stock guest driver; &amp;lt;code&amp;gt;[proven]&amp;lt;/code&amp;gt; hardware-format fact; &amp;lt;code&amp;gt;[hypothesis]&amp;lt;/code&amp;gt; unexercised; &amp;lt;code&amp;gt;[design]&amp;lt;/code&amp;gt; not built.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. What the GMMU is ==&lt;br /&gt;
&lt;br /&gt;
The '''GMMU (GPU Memory Management Unit)''' is the address-translation hardware inside the GPU. Every engine — GR (shaders and CUDA kernels), CE (copy engines), SEC2, the video engines — addresses memory through '''GPU virtual addresses (VAs)''', and the GMMU translates each VA into a physical address: an offset in GPU local memory ('''vidmem'''/VRAM), an address in system memory ('''sysmem'''), or a peer GPU's memory across a fabric.&lt;br /&gt;
&lt;br /&gt;
It is a paged MMU, conceptually the CPU MMU's sibling:&lt;br /&gt;
&lt;br /&gt;
* '''Multi-level page tables''' describe the mappings; the root is a '''page directory base (PDB)'''.&lt;br /&gt;
* A '''TLB''' caches translations so the walk is not paid per access.&lt;br /&gt;
* Translation failures raise '''faults''' (invalid/missing leaf, missing table), reported through engine fault buffers.&lt;br /&gt;
* '''Each context has its own page directory (VA space)''', so one context cannot name another context's mappings — this is the hardware isolation boundary the project builds multi-tenancy on.&lt;br /&gt;
&lt;br /&gt;
What makes it ''not'' just &amp;quot;the CPU MMU on a GPU&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* The tables live in GPU-visible memory (vidmem or sysmem), and each directory entry says which aperture the next level lives in.&lt;br /&gt;
* Entries carry GPU-specific '''aperture''' (which physical space) and '''memory-kind''' fields that the CPU MMU does not have.&lt;br /&gt;
* The &amp;quot;physical&amp;quot; addresses inside the tables are '''guest-physical addresses or emulated-VRAM offsets''' in our virtualized setting; the host module owns the resolution to real host addresses (§4.2). On a bare-metal GPU the same structures point at real vidmem/sysmem.&lt;br /&gt;
&lt;br /&gt;
For this project the GMMU matters three ways: the guest driver programs it exactly as on bare metal (no guest patches); the guest's page tables are the ground truth for ''where its memory actually is''; and the per-context page directory is the only proven hardware isolation primitive available on the reference generation (§4.2).&lt;br /&gt;
&lt;br /&gt;
== 2. The three MMUs: CPU MMU, GMMU, IOMMU/SMMU ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! &lt;br /&gt;
! CPU MMU&lt;br /&gt;
! GMMU&lt;br /&gt;
! IOMMU / SMMU&lt;br /&gt;
|-&lt;br /&gt;
| Translates&lt;br /&gt;
| process VA → host physical address&lt;br /&gt;
| engine GPU VA → GPU physical (vidmem / sysmem / peer)&lt;br /&gt;
| device DMA address → host physical address&lt;br /&gt;
|-&lt;br /&gt;
| Lives in&lt;br /&gt;
| the CPU core&lt;br /&gt;
| the GPU&lt;br /&gt;
| the host platform (IOMMU: Intel VT-d / AMD-Vi) or the SoC (SMMU, ARM)&lt;br /&gt;
|-&lt;br /&gt;
| Programmed by&lt;br /&gt;
| the OS kernel (per-process tables)&lt;br /&gt;
| the GPU driver / RM (the ''guest'' driver here)&lt;br /&gt;
| the hypervisor / OS (per-device or per-VM domains)&lt;br /&gt;
|-&lt;br /&gt;
| Table unit&lt;br /&gt;
| per-process page tables (e.g. CR3)&lt;br /&gt;
| per-context page directory (VA space)&lt;br /&gt;
| per-device/per-VM translation domain&lt;br /&gt;
|-&lt;br /&gt;
| Isolation scope&lt;br /&gt;
| process ↔ process&lt;br /&gt;
| context ↔ context (engine-level)&lt;br /&gt;
| VM/device ↔ VM/device (platform DMA)&lt;br /&gt;
|-&lt;br /&gt;
| In our stack&lt;br /&gt;
| guest and host kernels&lt;br /&gt;
| guest driver builds the tables; host walks or plants its own&lt;br /&gt;
| hypervisor enforces it; the module resolves GPAs itself when it needs host addresses&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
They are three instances of the same idea — ''page tables plus a TLB give virtual memory and isolation to an agent'' — at three different points in the address path, owned by three different software layers. In a virtualized guest a GPU access passes through '''two''' of them:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;engine (GR / CE)&lt;br /&gt;
   │  GPU VA&lt;br /&gt;
   ▼&lt;br /&gt;
GMMU  (inside the GPU, driven by the guest's page tables)&lt;br /&gt;
   │  guest physical address (GPA) / GPU local address&lt;br /&gt;
   ▼&lt;br /&gt;
IOMMU / SMMU  (in the host platform, programmed by the hypervisor for this VM)&lt;br /&gt;
   │  host physical address (HPA)&lt;br /&gt;
   ▼&lt;br /&gt;
host DRAM / real VRAM&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The two stages are independent: the '''GMMU''' decides ''which guest page'' an engine touches; the '''IOMMU/SMMU''' decides ''whether this device may reach that page at all'' and where it lives in host memory. GMMU isolation between guest contexts is the GPU driver/RM's job; IOMMU isolation between VMs is the platform's job.&lt;br /&gt;
&lt;br /&gt;
'''How the two meet in this project:'''&lt;br /&gt;
&lt;br /&gt;
* In real vGPU, the host vGPU manager uses the platform IOMMU to establish the GPU's view of guest memory. Here the host module does the equivalent resolution itself.&lt;br /&gt;
* On the reference host the physical GPU's IOMMU group is an '''identity domain''' (all-RAM identity) and the mediated device registers as an '''emulated-IOMMU VFIO device''': its type-1 container holds guest DMA mappings privately and no kernel &amp;lt;code&amp;gt;iommu_domain&amp;lt;/code&amp;gt; exists for it, so &amp;lt;code&amp;gt;iommu_iova_to_phys&amp;lt;/code&amp;gt; cannot translate guest GPAs. Guest RAM is backed by a QEMU shared file and the module translates GPA→HPA through that file's page cache, behind the active-mdev gate (a per-mdev-gated translation, ''not'' itself an IOMMU guarantee).&lt;br /&gt;
* The project rule is explicit: '''memory isolation is the platform IOMMU's job, and we never weaken it''' — DMA only through the hypervisor-provided interface for the device's own VM, no global mappings, fail closed if a required isolation property cannot be established.&lt;br /&gt;
* On aarch64 hosts the '''SMMU''' plays the IOMMU's role; page sizes, cache attributes and SMMU behaviour are on the host-portability list for the Grace/GB10 targets.&lt;br /&gt;
&lt;br /&gt;
== 3. How the GMMU works (Turing reference) ==&lt;br /&gt;
&lt;br /&gt;
=== 3.1 Page-tree geometry ===&lt;br /&gt;
&lt;br /&gt;
The Turing page-tree path inherits the Pascal/Volta geometry and uses the '''VER2''' entry encoding. Depths run root (0) to leaf (4); VA width is '''49 bits''':&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Depth&lt;br /&gt;
! HW level&lt;br /&gt;
! VA bits&lt;br /&gt;
! Index bits&lt;br /&gt;
! Entry size&lt;br /&gt;
! Role&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| PDE3&lt;br /&gt;
| 48:47&lt;br /&gt;
| 2&lt;br /&gt;
| 8 B&lt;br /&gt;
| pointer PDE&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| PDE2&lt;br /&gt;
| 46:38&lt;br /&gt;
| 9&lt;br /&gt;
| 8 B&lt;br /&gt;
| pointer PDE&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| PDE1&lt;br /&gt;
| 37:29&lt;br /&gt;
| 9&lt;br /&gt;
| 8 B&lt;br /&gt;
| pointer PDE (&amp;lt;code&amp;gt;NO_ATS&amp;lt;/code&amp;gt; set here)&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| PDE0&lt;br /&gt;
| 28:21&lt;br /&gt;
| 8&lt;br /&gt;
| 16 B (dual) / 8 B (2 MB leaf)&lt;br /&gt;
| dual 64K/4K PDE, or a 2 MB leaf PTE&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| PTE&lt;br /&gt;
| 20:12 (4 KB) / 20:16 (64 KB)&lt;br /&gt;
| 9 / 5&lt;br /&gt;
| 8 B&lt;br /&gt;
| leaf PTE&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Supported page sizes are '''2 MB''' (depth 3), '''64 KB''' and '''4 KB''' (depth 4). A leaf entry alone does not say 4 KB vs 64 KB — the table's depth and page-size context do — so decoders must report &amp;lt;code&amp;gt;4k_or_64k&amp;lt;/code&amp;gt; rather than guess.&lt;br /&gt;
&lt;br /&gt;
=== 3.2 Entry encoding (VER2) ===&lt;br /&gt;
&lt;br /&gt;
'''Leaf PTE (8 bytes):'''&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Bits&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;valid&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0&lt;br /&gt;
| entry is present&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;aperture&amp;lt;/code&amp;gt;&lt;br /&gt;
| 2:1&lt;br /&gt;
| 0 video, 1 peer, 2 system coherent, 3 system non-coherent&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;volatile&amp;lt;/code&amp;gt;&lt;br /&gt;
| 3&lt;br /&gt;
| cache/volatility bit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;encrypted&amp;lt;/code&amp;gt;&lt;br /&gt;
| 4&lt;br /&gt;
| encrypted memory&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;privilege&amp;lt;/code&amp;gt;&lt;br /&gt;
| 5&lt;br /&gt;
| privileged access&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;read_only&amp;lt;/code&amp;gt;&lt;br /&gt;
| 6&lt;br /&gt;
| write protection&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;atomic_disable&amp;lt;/code&amp;gt;&lt;br /&gt;
| 7&lt;br /&gt;
| atomics disabled&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;address_sys&amp;lt;/code&amp;gt;&lt;br /&gt;
| 53:8&lt;br /&gt;
| system-aperture address bits (PA 53:12)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;address_vid&amp;lt;/code&amp;gt;&lt;br /&gt;
| 32:8&lt;br /&gt;
| video/peer address bits (PA 36:12)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;peer_id&amp;lt;/code&amp;gt;&lt;br /&gt;
| 35:33&lt;br /&gt;
| peer/fabric id (peer aperture)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;comptagline&amp;lt;/code&amp;gt;&lt;br /&gt;
| 55:36&lt;br /&gt;
| compression tag (overloaded as high address bits for the 47-bit peer case)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;kind&amp;lt;/code&amp;gt;&lt;br /&gt;
| 63:56&lt;br /&gt;
| memory kind id&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Directory PDE (8 bytes)''' is the same shape with one discriminator change: bit 0 is &amp;lt;code&amp;gt;is_pde_pointer&amp;lt;/code&amp;gt; (0 = pointer to a lower table, 1 = a 2 MB leaf PTE), and '''aperture 0 means invalid at directory level''' (it means video memory at leaf level). Depth 2 sets &amp;lt;code&amp;gt;NO_ATS&amp;lt;/code&amp;gt; (bit 5).&lt;br /&gt;
&lt;br /&gt;
'''Dual PDE0 (16 bytes)''' holds two halves for mixed 64K/4K tables: BIG (low 64 bits) and SMALL (high 64 bits); bit 0 discriminates the whole slot.&lt;br /&gt;
&lt;br /&gt;
Live guest note: the client's leaf entries in the format we observe are &amp;lt;code&amp;gt;PA[47:12] | flags&amp;lt;/code&amp;gt;, with &amp;lt;code&amp;gt;flags = 0xe&amp;lt;/code&amp;gt; for a valid system-memory leaf. The &amp;lt;code&amp;gt;kind&amp;lt;/code&amp;gt; field carries numeric memory-kind ids (243 named values); common compute values are &amp;lt;code&amp;gt;0x00 PITCH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x06 GENERIC_MEMORY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x07 INVALID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x0F SMSKED_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0xFE GENERIC_16BX2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The decoder (&amp;lt;code&amp;gt;sim/gmmu_pte.py&amp;lt;/code&amp;gt;, docs/43) is decode-only: unsupported encodings fail closed, set bits not covered by a named field are reported as reserved, and nothing is guessed.&lt;br /&gt;
&lt;br /&gt;
=== 3.3 Walking, caching and faults ===&lt;br /&gt;
&lt;br /&gt;
A walk starts at the channel's '''page-directory base''' and follows &amp;lt;code&amp;gt;PDE3 → PDE2 → PDE1 → PDE0 → PTE&amp;lt;/code&amp;gt;; the leaf yields the physical address, page size, aperture and access permissions. The TLB caches results, and there is a second, coarser cache that matters operationally:&lt;br /&gt;
&lt;br /&gt;
* '''PTE fetch-line rule (learned live):''' the engine caches PTE fetches at '''128-byte (16-PTE) granularity''', and the forwarding code has '''no invalidate path'''. A runtime PTE write into a line the GMMU has already walked is invisible to the engine. Consequences: page-table slots for a guest window are '''pre-built before any engine access''', and each forwarded copy pair consumes a whole fresh line from a pre-zeroed pool (16 page-table pages, capacity 512 pairs per boot in the current design) — a line is never reused within a boot.&lt;br /&gt;
* '''Faults:''' invalid or missing leaves and missing tables raise GMMU faults; the driver allocates fault buffers whose sizes come from &amp;lt;code&amp;gt;INTERNAL_GMMU_GET_STATIC_INFO&amp;lt;/code&amp;gt; (control &amp;lt;code&amp;gt;0x20800a59&amp;lt;/code&amp;gt;): '''64 KB replayable / 4 KB legacy''' — the values the emulation serves, because a wrong value breaks UVM early.&lt;br /&gt;
&lt;br /&gt;
== 4. How the GMMU is used ==&lt;br /&gt;
&lt;br /&gt;
=== 4.1 Guest side (the stock driver) ===&lt;br /&gt;
&lt;br /&gt;
* The guest driver allocates VA spaces and '''builds the page tables''', then publishes the directory per channel/context through &amp;lt;code&amp;gt;SET_PAGE_DIRECTORY&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;hVASpace&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;chId&amp;lt;/code&amp;gt;; the host records the directory per owner in &amp;lt;code&amp;gt;kernel/gsp_rm_emulation.c:3307-3319&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Memory descriptors carry an aperture: &amp;lt;code&amp;gt;ADDR_SYSMEM = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ADDR_FBMEM = 2&amp;lt;/code&amp;gt;.&lt;br /&gt;
* '''Server-owned ranges:''' &amp;lt;code&amp;gt;COPY_SERVER_RESERVED_PDES&amp;lt;/code&amp;gt; (control &amp;lt;code&amp;gt;0x90f10106&amp;lt;/code&amp;gt;) tells the client that some page-table ranges are populated by the &amp;quot;server&amp;quot; (us). The exact division of labour for &amp;lt;code&amp;gt;RESERVE_ENTRIES&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;RELEASE_ENTRIES&amp;lt;/code&amp;gt; and invalidations is a tracked known-unknown.&lt;br /&gt;
* Channels submit push buffers that reference GPU VAs; the engines walk the GMMU to reach the data.&lt;br /&gt;
&lt;br /&gt;
=== 4.2 Host side (&amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt;) ===&lt;br /&gt;
&lt;br /&gt;
* '''Truth.''' The host resolves guest VAs by '''walking the driver-published page directories itself''' (the trusted GMMU walk in &amp;lt;code&amp;gt;kernel/gsp_sema_service.c&amp;lt;/code&amp;gt;, VER2 geometry at &amp;lt;code&amp;gt;:1058-1072&amp;lt;/code&amp;gt;, decode &amp;lt;code&amp;gt;:1093&amp;lt;/code&amp;gt;, walk &amp;lt;code&amp;gt;:1174&amp;lt;/code&amp;gt;), plus injected pins and content-keyed rescue when neither names a mapping. This is what lets the software path apply a semaphore release to the correct host page.&lt;br /&gt;
* '''Forwarding.''' For real CE copies the module builds its '''own scratch page tables''' that map already-resolved host pages (guest RAM through the shared file; shadow pages through the emulated-VRAM mapping), under the fetch-line rules of §3.3. Real guest page tables are ''not yet'' programmed into the real MMU — guest submission on hardware is the end state (P6).&lt;br /&gt;
* '''Emulation.''' Guest vidmem is a private host-RAM buffer per mdev (&amp;lt;code&amp;gt;kernel/bar_init.c:68-77&amp;lt;/code&amp;gt;); FB-aperture accesses stay inside the owning mdev's buffer, and guest RAM is reached only through the hypervisor's per-mdev DMA interface (&amp;lt;code&amp;gt;vfio_dma_rw&amp;lt;/code&amp;gt;).&lt;br /&gt;
* '''Isolation.''' The per-context page directory is the '''only proven hardware isolation primitive''' on this generation: the VER2 PTE/PDE has '''no tenant/ACL/PASID field''' (proven absence in the named field set; &amp;lt;code&amp;gt;peer_id&amp;lt;/code&amp;gt; is a fabric peer selector, not a security domain). &amp;lt;code&amp;gt;read_only&amp;lt;/code&amp;gt; (bit 6) is a proven ''format'' field, but its ''enforcement'' is a &amp;lt;code&amp;gt;[hypothesis]&amp;lt;/code&amp;gt; until the M7 supervised probe. The multi-tenant design therefore places decisions in '''topology''' (which directory a page appears in, which channel may name it) plus software validation and audit in the execution plane — see [[GMMU Multi-Tenant Protection|&amp;lt;code&amp;gt;GMMU-Multi-Tenant-Protection.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
* '''Versioning.''' GMMU controls, static info and entry formats are version/hardware-keyed; formats are expected to differ per generation and must be re-derived by measurement, never guessed.&lt;br /&gt;
&lt;br /&gt;
=== 4.3 Tooling built around it ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tool / doc&lt;br /&gt;
! Question it answers&lt;br /&gt;
|-&lt;br /&gt;
| PTE decoder &amp;lt;code&amp;gt;sim/gmmu_pte.py&amp;lt;/code&amp;gt; + [https://git.vgpu.io/open-iov/blob/master/debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md docs/43]&lt;br /&gt;
| decode a captured entry field-by-field (decode-only, fail closed)&lt;br /&gt;
|-&lt;br /&gt;
| Walker &amp;lt;code&amp;gt;sim/gmmu_walk.py&amp;lt;/code&amp;gt; + [https://git.vgpu.io/open-iov/blob/master/debug/risc-v-gsp-rm-vm/docs/48-GMMU-WALK-AND-LAUNCH-AUDIT.md docs/48]&lt;br /&gt;
| walk a captured PDB to the leaf mapping or the exact fault (4K/2M validated against a live captured channel PDB; 64K modelled)&lt;br /&gt;
|-&lt;br /&gt;
| Launch audit &amp;lt;code&amp;gt;harness/launch_audit.py&amp;lt;/code&amp;gt; + docs/48&lt;br /&gt;
| where the engine would read/write each leg of a submission: &amp;lt;code&amp;gt;ok&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;pa_mismatch&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;unmapped&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;access_denied&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Oracle workflow [https://git.vgpu.io/open-iov/blob/master/debug/risc-v-gsp-rm-vm/docs/44-GMMU-ORACLE-AND-WORKFLOW.md docs/44]&lt;br /&gt;
| compare simulated vs observed GMMU/FBIF register values, per register, with fidelity labels&lt;br /&gt;
|-&lt;br /&gt;
| Observe-only windows [https://git.vgpu.io/open-iov/blob/master/debug/risc-v-gsp-rm-vm/docs/42-GMMU-FBIF-OBSERVABILITY.md docs/42]&lt;br /&gt;
| record what firmware touches in the GMMU register windows without faking semantics&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 5. Limits and open questions ==&lt;br /&gt;
&lt;br /&gt;
* '''&amp;lt;code&amp;gt;read_only&amp;lt;/code&amp;gt; enforcement''' is unproven (M7 supervised probe); '''encryption (CCS) semantics''' are unstudied. Neither can be assumed as a tenant boundary.&lt;br /&gt;
* '''Invalidation semantics''' are not fully modelled: the 128-byte fetch-line observation is live evidence, not a complete invalidate contract.&lt;br /&gt;
* The '''64K dual path''' is modelled from the format definitions, not yet validated against a capture.&lt;br /&gt;
* '''Newer generations''' (Ampere/Hopper/Blackwell, GB10) are expected to change the entry format; each must be re-derived. RM 610 work sits behind its own human approval gate.&lt;br /&gt;
* '''No timing/cycle claims''' are made anywhere here; zero hits in a run are a coverage fact, not proof of dead code.&lt;br /&gt;
* Multi-mdev isolation is first a '''service-state-ownership''' problem (host tables keyed by guest-chosen handles/VAs alone collide); GMMU policy is built on top of that fix, not instead of it.&lt;br /&gt;
&lt;br /&gt;
== 6. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/05-gmmu-amap-hal-gr.md &amp;lt;code&amp;gt;../docs/03-architecture/05-gmmu-amap-hal-gr.md&amp;lt;/code&amp;gt;] — architecture chapter: GMMU, AMAPlib/HALs, channels, runlists, GR.&lt;br /&gt;
* [[GMMU Multi-Tenant Protection|&amp;lt;code&amp;gt;GMMU-Multi-Tenant-Protection.md&amp;lt;/code&amp;gt;]] — the isolation design condensed.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/14-multi-tenant-gmmu-protection.md &amp;lt;code&amp;gt;../docs/03-architecture/14-multi-tenant-gmmu-protection.md&amp;lt;/code&amp;gt;] — canonical multi-tenant GMMU policy.&lt;br /&gt;
* [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]] — how guest work becomes physical execution; the fetch-line rule in context.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/11-physical-backend-guest-wiring.md &amp;lt;code&amp;gt;../docs/03-architecture/11-physical-backend-guest-wiring.md&amp;lt;/code&amp;gt;] — page-table seams and the guest-memory reachability model.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/04-implementation/01-known-knowns-and-unknowns.md &amp;lt;code&amp;gt;../docs/04-implementation/01-known-knowns-and-unknowns.md&amp;lt;/code&amp;gt;] — server-owned page tables and the IOMMU reachability note.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/05-operations/01-performance-correctness-security.md &amp;lt;code&amp;gt;../docs/05-operations/01-performance-correctness-security.md&amp;lt;/code&amp;gt;] — threat model and the IOMMU rules.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md &amp;lt;code&amp;gt;../debug/risc-v-gsp-rm-vm/docs/43-GMMU-PTE-DECODER.md&amp;lt;/code&amp;gt;], [https://git.vgpu.io/open-iov/blob/master/debug/risc-v-gsp-rm-vm/docs/44-GMMU-ORACLE-AND-WORKFLOW.md docs/44], [https://git.vgpu.io/open-iov/blob/master/debug/risc-v-gsp-rm-vm/docs/48-GMMU-WALK-AND-LAUNCH-AUDIT.md docs/48] — the field catalogue and the offline walk/audit tooling.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Install_and_First_Run&amp;diff=23948</id>
		<title>Install and First Run</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Install_and_First_Run&amp;diff=23948"/>
		<updated>2026-10-12T04:29:49Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Install and First Run =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''What this page is.''' From a fresh Ubuntu host with a supported NVIDIA GPU to a guest VM running a stock NVIDIA driver and &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt;, in about half an hour. Condensed from the maintained guide [https://git.vgpu.io/open-iov/blob/master/docs/02-getting-started/01-install-and-first-run.md &amp;lt;code&amp;gt;../docs/02-getting-started/01-install-and-first-run.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; verified path; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; roadmap item.&lt;br /&gt;
&lt;br /&gt;
== 1. Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
'''Host'''&lt;br /&gt;
&lt;br /&gt;
* Ubuntu 22.04 or 24.04, x86_64 (aarch64 is a &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt;);&lt;br /&gt;
* an NVIDIA GPU covered by the current emulation profile (Turing TU104 is the reference — see [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]]);&lt;br /&gt;
* a working '''host''' NVIDIA driver (&amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; runs on the host; Open-IOV does not modify it);&lt;br /&gt;
* IOMMU enabled (&amp;lt;code&amp;gt;intel_iommu=on&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;amd_iommu=on&amp;lt;/code&amp;gt;), hugepages configured, kernel headers for the running kernel;&lt;br /&gt;
* &amp;lt;code&amp;gt;qemu-system-x86_64&amp;lt;/code&amp;gt; with KVM; libvirt optional;&lt;br /&gt;
* root (or sudo) for module load and mdev creation.&lt;br /&gt;
&lt;br /&gt;
'''Guest'''&lt;br /&gt;
&lt;br /&gt;
* Ubuntu 24.04 server (the reference guest), or any Linux with the matching stock NVIDIA driver available;&lt;br /&gt;
* '''no Open-IOV component at all''' — that is the point ([[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 2. Get the code and build ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;git clone https://git.vgpu.io/open-iov.git&lt;br /&gt;
cd open-iov&lt;br /&gt;
./install.sh deps        # build/runtime dependencies&lt;br /&gt;
./install.sh nvidia      # optional: NVIDIA OpenRM modules + build glue&lt;br /&gt;
./install.sh firmware    # GSP firmware image (verified)&lt;br /&gt;
./install.sh build       # kernel module + userspace&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;install.sh&amp;lt;/code&amp;gt; is safe to re-run. The manual equivalent, and the order that matters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;make kernel                      # first: generates Module.symvers&lt;br /&gt;
./scripts/build_nvidia_openrm.sh # optional (see below)&lt;br /&gt;
make userspace&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Build order matters.''' NVIDIA's OpenRM modules resolve symbols that &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt; exports; building them in the wrong order produces &amp;lt;code&amp;gt;Unknown symbol&amp;lt;/code&amp;gt; failures at load time.&lt;br /&gt;
&lt;br /&gt;
'''The OpenRM stage is optional.''' It is needed only for the native vGPU-management workflows in which NVIDIA's modules are built against the symbols &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt; exports. The QEMU/emulated path uses the distribution driver that already manages the physical GPU; &amp;lt;code&amp;gt;load-stack&amp;lt;/code&amp;gt; skips the OpenRM submodule when a distribution driver is present.&lt;br /&gt;
&lt;br /&gt;
== 3. Load the stack and create a virtual GPU ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;./scripts/stack_manager.sh status        # what is currently loaded&lt;br /&gt;
./scripts/stack_manager.sh load-stack    # vfio/mdev prereqs -&amp;amp;gt; vgsp.ko -&amp;amp;gt; (optional) nvidia&lt;br /&gt;
./scripts/stack_manager.sh mdev-create   # create a vGPU mediated device&lt;br /&gt;
./scripts/stack_manager.sh mdev-list     # inspect /sys/bus/mdev/devices/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The mdev device ''is'' the virtual GPU; everything after this treats it like any other VFIO device.&lt;br /&gt;
&lt;br /&gt;
== 4. Launch a reference guest ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;./scripts/stack_manager.sh qemu          # reference raw-QEMU guest with the mdev&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To integrate with your own stack (libvirt, Xen, ...), attach the mdev exactly as any VFIO device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;amp;lt;hostdev mode='subsystem' type='mdev' model='vfio-pci'&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;source&amp;amp;gt;&lt;br /&gt;
    &amp;amp;lt;address uuid='&amp;amp;lt;mdev-uuid&amp;amp;gt;'/&amp;amp;gt;&lt;br /&gt;
  &amp;amp;lt;/source&amp;amp;gt;&lt;br /&gt;
&amp;amp;lt;/hostdev&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Attach behind a root port, not on the root bus.''' QEMU rewrites a device's PCIe capability when it detects a root-complex-integrated endpoint, which changes the link capabilities the guest driver sees. The reference script does this for you.&lt;br /&gt;
&lt;br /&gt;
== 5. Install the stock driver in the guest ==&lt;br /&gt;
&lt;br /&gt;
Inside the guest:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apt update&lt;br /&gt;
sudo apt install -y linux-headers-generic build-essential&lt;br /&gt;
# The validated combination is the stock 570.144 Linux runfile (the same&lt;br /&gt;
# driver version as the emulation target).&lt;br /&gt;
sudo sh ./NVIDIA-Linux-x86_64-570.144.run&lt;br /&gt;
sudo reboot&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;nvidia-smi                # must list the virtual GPU&lt;br /&gt;
lsmod | grep -c nvidia&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt; fails to probe, capture host dmesg, guest dmesg, guest &amp;lt;code&amp;gt;lspci -vvv&amp;lt;/code&amp;gt; and the guest module parameters, and file an issue.&lt;br /&gt;
&lt;br /&gt;
== 6. First CUDA check ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# in the guest&lt;br /&gt;
git clone https://github.com/NVIDIA/cuda-samples.git&lt;br /&gt;
cd cuda-samples/Samples/1_Utilities/deviceQuery &amp;amp;amp;&amp;amp;amp; make &amp;amp;amp;&amp;amp;amp; ./deviceQuery&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Expectation today''' (&amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; unless noted): driver probe, &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt;, device enumeration and the full CUDA '''driver-API''' smoke complete end to end (&amp;lt;code&amp;gt;ALL OK&amp;lt;/code&amp;gt;, 64-byte payload round-trips). CUDA '''kernel execution''' is the current frontier: a guest launch is forwarded and reaches the engine queue, but engine execution is not yet observed (&amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt;) — see [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] and [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]] before drawing conclusions from a kernel that does not run.&lt;br /&gt;
&lt;br /&gt;
== 7. Day-to-day operations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;./scripts/stack_manager.sh up          # build all + load + create mdev&lt;br /&gt;
./scripts/stack_manager.sh status      # modules, mdev, vfio, firmware&lt;br /&gt;
./scripts/stack_manager.sh test        # host test suite&lt;br /&gt;
./scripts/stack_manager.sh unload      # correct-order teardown&lt;br /&gt;
./scripts/stack_manager.sh cleanup-crash&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Load order is prerequisites → kernel module → (optional) NVIDIA OpenRM → firmware; unload is the reverse. Do not &amp;lt;code&amp;gt;rmmod&amp;lt;/code&amp;gt; by hand while a VM holds the mdev.&lt;br /&gt;
&lt;br /&gt;
== 8. Watching the emulation work ==&lt;br /&gt;
&lt;br /&gt;
The module logs with the prefix '''&amp;lt;code&amp;gt;vgsp-&amp;amp;lt;subsystem&amp;amp;gt;:&amp;lt;/code&amp;gt;''' (for example &amp;lt;code&amp;gt;vgsp-rpc:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;vgsp-sema:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;vgsp-work:&amp;lt;/code&amp;gt;) plus per-RPC traces:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo dmesg -w | grep -i 'vgsp'          # live&lt;br /&gt;
sudo dmesg -T | grep -i 'vgsp' | tail -50&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Developer debug knobs (module parameters) are documented in the repository's debugging workflow document.&lt;br /&gt;
&lt;br /&gt;
== 9. Troubleshooting index ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Symptom&lt;br /&gt;
! Start here&lt;br /&gt;
|-&lt;br /&gt;
| Module will not load&lt;br /&gt;
| &amp;lt;code&amp;gt;dmesg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;modinfo vgsp.ko&amp;lt;/code&amp;gt;, stale module state → &amp;lt;code&amp;gt;cleanup-crash&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| No mdev type for your GPU&lt;br /&gt;
| [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
|-&lt;br /&gt;
| Guest sees wrong PCIe link speed/width&lt;br /&gt;
| attach behind a root port (section 4)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt; probe fails in guest&lt;br /&gt;
| guest dmesg + &amp;lt;code&amp;gt;lspci -vvv&amp;lt;/code&amp;gt; + [[Guest Driver Lifecycle: A Field Guide|&amp;lt;code&amp;gt;Driver-Lifecycle-Field-Guide.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; works, a CUDA kernel does not run&lt;br /&gt;
| expected today — the execution frontier, not your setup ([[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]])&lt;br /&gt;
|-&lt;br /&gt;
| VM boot fails or the guest hangs&lt;br /&gt;
| &amp;lt;code&amp;gt;scripts/stack_manager.sh cleanup-crash&amp;lt;/code&amp;gt;, then reboot&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 10. Uninstall ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;./scripts/stack_manager.sh unload&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The project never modifies your host driver's files; removing the module and its mdev devices returns the host to its previous state.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=The_Host_Module_(vgsp.ko)&amp;diff=23947</id>
		<title>The Host Module (vgsp.ko)</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=The_Host_Module_(vgsp.ko)&amp;diff=23947"/>
		<updated>2026-10-12T04:29:48Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= The Host Module (vgsp.ko) =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Scope.''' The host-side kernel module that presents one virtual Turing-class GPU per &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; instance: the virtual device, the emulation engine, the guest-memory model and the work-forwarding design. Canonical source: [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;]; the docs tree wins on disagreement with this page.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[live]&amp;lt;/code&amp;gt; observed with the stock guest driver; &amp;lt;code&amp;gt;[wip]&amp;lt;/code&amp;gt; demonstrated live, being productized; &amp;lt;code&amp;gt;[gated]&amp;lt;/code&amp;gt; implemented default-off behind supervised gates; &amp;lt;code&amp;gt;[wall]&amp;lt;/code&amp;gt; known blocking limit; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; designed, not built; &amp;lt;code&amp;gt;[planned]&amp;lt;/code&amp;gt; roadmap.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 1. Role and position ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;guest VM ── PCIe MMIO / DMA / MSI-X through the hypervisor&lt;br /&gt;
   (KVM/QEMU or Xen: VFIO mdev transport, IOMMU)&lt;br /&gt;
   │&lt;br /&gt;
vgsp.ko: virtual device · emulation core · memory model · work path&lt;br /&gt;
   │&lt;br /&gt;
physical GPU + GSP firmware, driven by this module (host driver unmodified)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The module registers as an '''mdev parent''' on the physical GPU, exposing one device type per supported profile; each &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; is an independent virtual GPU ([[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]], [[The vGSP Execution Plane (vEP)|&amp;lt;code&amp;gt;Execution-Plane.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 2. The virtual device ==&lt;br /&gt;
&lt;br /&gt;
The guest sees a plausible Turing-class GPU (IDs, class code, BARs, capability list). Some fields exist only for validation: PCIe link capabilities (the hypervisor can rewrite them), MSI-X masking state, and non-SR-IOV VF windows.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! BAR&lt;br /&gt;
! Size&lt;br /&gt;
! Backing&lt;br /&gt;
! Contents&lt;br /&gt;
|-&lt;br /&gt;
| BAR0&lt;br /&gt;
| 16 MB&lt;br /&gt;
| host &amp;lt;code&amp;gt;vzalloc&amp;lt;/code&amp;gt; shadow&lt;br /&gt;
| boot, doorbells, VF registers, PRAMIN window, VBIOS&lt;br /&gt;
|-&lt;br /&gt;
| BAR1&lt;br /&gt;
| 256 MB&lt;br /&gt;
| host &amp;lt;code&amp;gt;vzalloc&amp;lt;/code&amp;gt; vidmem buffer&lt;br /&gt;
| guest-visible VRAM aperture&lt;br /&gt;
|-&lt;br /&gt;
| BAR3&lt;br /&gt;
| —&lt;br /&gt;
| instance window&lt;br /&gt;
| instance/PRAMIN behaviour&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
MMIO is served by VFIO region callbacks or directly from the shadow when mapped into the guest. BAR1 is host RAM today — correctness first: the real GPU cannot read it, so forwarding must later migrate objects to real VRAM or expose DMA-mapped system memory [target] ([[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 3. The emulation core ==&lt;br /&gt;
&lt;br /&gt;
A kernel thread drives the device's &amp;quot;firmware&amp;quot; behaviour [live]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BAR0 doorbell / VF-register write → read msgq element from guest memory&lt;br /&gt;
   → dispatch RPC → write reply → inject MSI-X (eventfd → irqfd)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Guest memory is reached via &amp;lt;code&amp;gt;vfio_dma_rw()&amp;lt;/code&amp;gt; from kernel-thread context. The RPC philosophy: correct shape first (or the driver walks off into uninitialized memory), plausible values second (values must be self-consistent), never invent input (in/out parameter blocks are echoed; zeroing the &amp;lt;code&amp;gt;GSP_RM_ALLOC&amp;lt;/code&amp;gt; reply once faulted &amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt;). Handlers cover boot/static-info exchanges, device/FB/BUS/INTR tables, CE and GMMU queries, reserved-PDE contracts, channel/CE allocation and an unknown-control fallback. Push buffers are decoded as method streams and executed in software — memsets, copies, semaphore releases — a '''correctness bridge, not the data plane''' [wip]; emulation-mode CUDA is verified end to end (&amp;lt;code&amp;gt;vectorAdd&amp;lt;/code&amp;gt; over 1M elements, &amp;lt;code&amp;gt;bad=0&amp;lt;/code&amp;gt;) [live]. Physical-GSP boot is default-off [gated]; the firmware analyzer, version tables, HAL tables and dynamic RPC dispatcher are not yet on the live path [target].&lt;br /&gt;
&lt;br /&gt;
== 4. The guest-memory model ==&lt;br /&gt;
&lt;br /&gt;
'''What the client gives us:''' channel memory descriptors (&amp;lt;code&amp;gt;NV_MEMORY_DESC_PARAMS&amp;lt;/code&amp;gt;) with ''physical'' addresses (instance memory, method buffer, userd, ramfc, error notifiers) and the page-table contract for server-owned VA ranges (&amp;lt;code&amp;gt;COPY_SERVER_RESERVED_PDES&amp;lt;/code&amp;gt; — table-level PAs, page shifts, VA range, ''empty'' leaves). It gives us none of its own sysmem maps.&lt;br /&gt;
&lt;br /&gt;
'''What we derive instead''' [live] — the module rebuilds the missing mappings from the guest's own bookkeeping, with no cooperation from the guest driver:&lt;br /&gt;
&lt;br /&gt;
# '''VA↔PA pairs live in guest memory''': UVM and RM record both the GPU VA and the kernel CPU VA per object (&amp;lt;code&amp;gt;uvm_rm_mem_t.vas[CPU]/vas[GPU]&amp;lt;/code&amp;gt; +0x30/+0x38).&lt;br /&gt;
# '''CPU VAs are direct-map addresses''': &amp;lt;code&amp;gt;PA = cpu_va - page_offset_base&amp;lt;/code&amp;gt;, the base recovered from guest memory or &amp;lt;code&amp;gt;/proc/kallsyms&amp;lt;/code&amp;gt; during development.&lt;br /&gt;
# '''Exception:''' control-device &amp;lt;code&amp;gt;mmap()&amp;lt;/code&amp;gt; pages have no leaf PTEs; verified pairs arrive via &amp;lt;code&amp;gt;sema_map_add&amp;lt;/code&amp;gt; until a durable join exists. The page-granular cache is fed by a trusted GMMU walk ([[Introduction to GMMU|&amp;lt;code&amp;gt;Introduction-to-GMMU.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
'''Load-bearing copy invariants:''' (1) a copy runs at most once per GPFIFO entry — replays are suppressed by entry-word identity plus an executed-operation bitmap; (2) a virtual operand translates per 4 KB page (195 of 256 pages were contiguous in one observed 1 MB range); (3) a consumed slot's work never runs later — the per-put-epoch mark is authoritative until a put wrap.&lt;br /&gt;
&lt;br /&gt;
== 5. The forwarding path (design) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;guest push submitted&lt;br /&gt;
   → detect (doorbell / GPPUT / push-buffer scan), decode the method stream&lt;br /&gt;
   → EMULATE state/notification (release, membar, fence) or&lt;br /&gt;
     FORWARD real engine work (GR launch, CE copy, memop)&lt;br /&gt;
   → FORWARD: submit equivalent work on a real channel bound to the physical GPU&lt;br /&gt;
   → relay completions (semaphore / fault / interrupt) back into guest memory&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Proxying through the distribution host driver has '''no callable entry point from kernel context''', so the module '''owns the device and runs its real GSP firmware as the resource-manager server''', with emulation as the control plane. CE copies, release and fault relay are implemented default-off and verified live [gated]; GR execution is the open wall [wall] — a forwarded launch reaches the front-end; the inline launch-descriptor install is unobserved ([[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]).&lt;br /&gt;
&lt;br /&gt;
== 6. Debug parameters ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;/sys/module/vgsp/parameters/*&amp;lt;/code&amp;gt; makes guest memory and the emulated device inspectable without rebuilding:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Parameter&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;scan_guest_ram=&amp;amp;lt;v&amp;amp;gt;&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;scan_vidmem=&amp;amp;lt;v&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| find a 64-bit value in guest RAM (0–8 GB) or the VRAM shadow&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;scan_seq=&amp;amp;lt;v1,...&amp;amp;gt;&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;scan_pt=&amp;amp;lt;pa&amp;amp;gt;&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;scan_masked=&amp;amp;lt;v&amp;amp;gt;,&amp;amp;lt;mask&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| find a 32-bit sequence, entries pointing at a PA, or &amp;lt;code&amp;gt;(x &amp;amp;amp; mask) == v&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dump_vidmem=&amp;amp;lt;off&amp;amp;gt;,&amp;amp;lt;len&amp;amp;gt;&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;fill_vidmem=&amp;amp;lt;v&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| dump/scan or fill the VRAM shadow&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;poke_guest=&amp;amp;lt;gpa&amp;amp;gt;,&amp;amp;lt;v&amp;amp;gt;&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;poke_fill=&amp;amp;lt;gpa&amp;amp;gt;,&amp;amp;lt;v&amp;amp;gt;,&amp;amp;lt;n&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| write a 32-bit value / fill a range in guest physical memory&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;sema_probe=&amp;amp;lt;gpu_va&amp;amp;gt;[,count]&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;sema_map_add=&amp;amp;lt;va&amp;amp;gt;,&amp;amp;lt;pa&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| probe a semaphore VA / teach one verified VA→PA pair&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dump_guest=&amp;amp;lt;gpa&amp;amp;gt;,&amp;amp;lt;len&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
| dump guest physical memory (capped)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The physical-backend path adds a default-off set of backend controls (documented in the repository; workflows in [https://git.vgpu.io/open-iov/blob/master/docs/05-operations/02-debugging-and-maintenance-workflows.md &amp;lt;code&amp;gt;../docs/05-operations/02-debugging-and-maintenance-workflows.md&amp;lt;/code&amp;gt;]).&lt;br /&gt;
&lt;br /&gt;
== 7. Build and symbol contracts ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;vgsp.ko&amp;lt;/code&amp;gt; exports the &amp;lt;code&amp;gt;nvidia_vgpu_vfio_*&amp;lt;/code&amp;gt; interface (&amp;lt;code&amp;gt;probe&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;remove&amp;lt;/code&amp;gt;, ops get/set, mdev parent registration) to pair the device with OpenRM host modules.&lt;br /&gt;
* OpenRM modules built from source need &amp;lt;code&amp;gt;KBUILD_EXTRA_SYMBOLS=$(pwd)/kernel/Module.symvers&amp;lt;/code&amp;gt; and must build '''after''' this module (missing symbols and stale build caches are common otherwise).&lt;br /&gt;
* On single-GPU developer systems the distribution driver owns the physical GPU and the module runs standalone; the OpenRM path is only for native-vGPU management, not QEMU.&lt;br /&gt;
&lt;br /&gt;
== 8. Implemented vs designed ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Area&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| mdev/VFIO device, config space, BARs, MSI-X; BAR0 state machine; boot handshake [live]&lt;br /&gt;
| implemented&lt;br /&gt;
|-&lt;br /&gt;
| Message queues + RPC + init controls (stock 570.144) [live]&lt;br /&gt;
| implemented&lt;br /&gt;
|-&lt;br /&gt;
| Guest sysmem access + VA↔PA discovery [wip]&lt;br /&gt;
| debug-grade, to be productized&lt;br /&gt;
|-&lt;br /&gt;
| Push decoding + semaphore completion [wip]&lt;br /&gt;
| demonstrated live, being productized&lt;br /&gt;
|-&lt;br /&gt;
| Emulation-mode CUDA end-to-end [live]&lt;br /&gt;
| repeatable 1M-element &amp;lt;code&amp;gt;vectorAdd&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bad=0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Guest-RAM physical path + server-owned page-table population [gated]&lt;br /&gt;
| default-off; GPA→HPA via shared-file page cache verified live on the CE&lt;br /&gt;
|-&lt;br /&gt;
| GPU work forwarding: CE copy, release and fault relay [gated]&lt;br /&gt;
| default-off, verified live; GR open [wall]&lt;br /&gt;
|-&lt;br /&gt;
| Execution backend (module-owned GPU, direct real-GSP session) [wall]&lt;br /&gt;
| boot, static configuration and CE copies proven; GR execution open (failed mutating attempts park the device in a locked fail-safe, never auto-retried)&lt;br /&gt;
|-&lt;br /&gt;
| Real VRAM backing [target]; Windows, Xen, aarch64 [planned]&lt;br /&gt;
| designed, not implemented&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 9. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* Canonical chapter: [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/06-host-module-and-hybrid-model.md &amp;lt;code&amp;gt;../docs/03-architecture/06-host-module-and-hybrid-model.md&amp;lt;/code&amp;gt;] — the source of this condensation.&lt;br /&gt;
* [[GSP RPC Emulation|&amp;lt;code&amp;gt;GSP-RPC-Emulation.md&amp;lt;/code&amp;gt;]], [[BAR Emulation Specification|&amp;lt;code&amp;gt;BAR-Emulation-Specification.md&amp;lt;/code&amp;gt;]], [[WPR Management|&amp;lt;code&amp;gt;WPR-Management.md&amp;lt;/code&amp;gt;]]; [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]], [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]], [[The Guest Stack and CUDASW|&amp;lt;code&amp;gt;Guest-Stack-and-CUDASW.md&amp;lt;/code&amp;gt;]].&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=Hardware_and_Software_Matrix&amp;diff=23946</id>
		<title>Hardware and Software Matrix</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=Hardware_and_Software_Matrix&amp;diff=23946"/>
		<updated>2026-10-12T04:29:47Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= Hardware and Software Matrix =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Companion summary.''' This page condenses [https://git.vgpu.io/open-iov/blob/master/docs/06-portability/hardware-software-matrix.md &amp;lt;code&amp;gt;../docs/06-portability/hardware-software-matrix.md&amp;lt;/code&amp;gt;] — the canonical support matrix: the support ladder, the current status of every host/GPU/guest/hypervisor combination, and what adding a combination requires. The validation process behind every support decision is [https://git.vgpu.io/open-iov/blob/master/docs/06-portability/03-device-validation-and-porting-sequence.md &amp;lt;code&amp;gt;../docs/06-portability/03-device-validation-and-porting-sequence.md&amp;lt;/code&amp;gt;]. When this page and the docs tree disagree, the docs tree wins. Front door: [https://git.vgpu.io/open-iov/blob/master/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[reference]&amp;lt;/code&amp;gt; continuously tested, bugs block releases; &amp;lt;code&amp;gt;[supported]&amp;lt;/code&amp;gt; tested per release; &amp;lt;code&amp;gt;[experimental]&amp;lt;/code&amp;gt; partial or bring-up; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; designed for, bring-up in progress; &amp;lt;code&amp;gt;[design]&amp;lt;/code&amp;gt; design direction, not the current build.&lt;br /&gt;
&lt;br /&gt;
== 1. Support ladder ==&lt;br /&gt;
&lt;br /&gt;
Support means '''tested and documented''', not &amp;quot;should probably work&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Level&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| '''Reference'''&lt;br /&gt;
| continuously tested; bugs block releases&lt;br /&gt;
|-&lt;br /&gt;
| '''Supported'''&lt;br /&gt;
| tested per release; documented workarounds if any&lt;br /&gt;
|-&lt;br /&gt;
| '''Experimental'''&lt;br /&gt;
| known to boot/test partially; may need configuration&lt;br /&gt;
|-&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| architecture designed for it; bring-up in progress&lt;br /&gt;
|-&lt;br /&gt;
| '''Out of scope'''&lt;br /&gt;
| not planned&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 2. Host platforms ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Platform&lt;br /&gt;
! Status&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| x86_64 + NVIDIA Turing (TU104)&lt;br /&gt;
| '''Reference'''&lt;br /&gt;
| the development hardware (RTX 2080-class); the only Reference platform today&lt;br /&gt;
|-&lt;br /&gt;
| x86_64 + Ampere / Ada consumer&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| profile work; expected to be configuration + measurement&lt;br /&gt;
|-&lt;br /&gt;
| x86_64 + Hopper / datacenter&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| requires MIG-aware policy for multi-tenancy&lt;br /&gt;
|-&lt;br /&gt;
| aarch64 + Grace-Hopper (GH200)&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| host-architecture work in the memory model&lt;br /&gt;
|-&lt;br /&gt;
| aarch64 + Grace-Blackwell&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| as above, newer firmware/driver family&lt;br /&gt;
|-&lt;br /&gt;
| GB10 (DGX Spark, Surface-class RTX laptops)&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| same architecture; firmware/ROM quirks to be measured&lt;br /&gt;
|-&lt;br /&gt;
| Other NVIDIA generations&lt;br /&gt;
| '''Experimental'''&lt;br /&gt;
| bring-up path in the canonical document §5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The design direction is that '''each new host platform should require configuration + verification, not new code''' — not the current state: selection is compile-time today and the module is built for the TU104 profile.&lt;br /&gt;
&lt;br /&gt;
== 3. Guest operating systems ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Guest&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| Linux x86_64 (stock &amp;lt;code&amp;gt;nvidia.ko&amp;lt;/code&amp;gt;, CUDA)&lt;br /&gt;
| '''Experimental''' — probe, &amp;lt;code&amp;gt;nvidia-smi&amp;lt;/code&amp;gt; and the driver-API smoke pass; CE-class copies are forwarded default-off; for GR the guest launch reaches the front-end but no grid has dispatched yet (see [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]); no continuous guest testing yet&lt;br /&gt;
|-&lt;br /&gt;
| Linux aarch64&lt;br /&gt;
| '''Target'''&lt;br /&gt;
|-&lt;br /&gt;
| Windows x86_64 (WDDM driver, CUDA, 3D)&lt;br /&gt;
| '''Target'''&lt;br /&gt;
|-&lt;br /&gt;
| Other Unix (FreeBSD, ...)&lt;br /&gt;
| Out of scope until demand&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Guest rule:''' the guest never contains Open-IOV code — no guest agent, no driver patch, no kernel parameters beyond what the stock driver needs.&lt;br /&gt;
&lt;br /&gt;
== 4. Hypervisors and transports ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Hypervisor&lt;br /&gt;
! Status&lt;br /&gt;
! Transport&lt;br /&gt;
|-&lt;br /&gt;
| KVM + QEMU (VFIO mdev)&lt;br /&gt;
| '''Reference'''&lt;br /&gt;
| VFIO mdev + eventfd IRQ + DMA interface&lt;br /&gt;
|-&lt;br /&gt;
| libvirt (mdev attach)&lt;br /&gt;
| '''Supported'''&lt;br /&gt;
| same, via libvirt XML&lt;br /&gt;
|-&lt;br /&gt;
| Zen / KVM on other device models&lt;br /&gt;
| '''Experimental'''&lt;br /&gt;
| as above&lt;br /&gt;
|-&lt;br /&gt;
| Xen (incl. Argo/OpenXT)&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| Xen device model + event channels&lt;br /&gt;
|-&lt;br /&gt;
| Qubes OS / Qubes OS Air&lt;br /&gt;
| '''Target'''&lt;br /&gt;
| compartmentalized VMs; GPU per compartment&lt;br /&gt;
|-&lt;br /&gt;
| Cloud hypervisor / crosvm&lt;br /&gt;
| '''Experimental'''&lt;br /&gt;
| VFIO-based; needs testing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The transport boundary — registration, guest-memory access, interrupt injection — is deliberately narrow, so a new transport is small and isolated.&lt;br /&gt;
&lt;br /&gt;
== 5. What portability means today ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;   host architecture        GPU family            driver/firmware family&lt;br /&gt;
   ┌─────────────────┐   ┌──────────────────┐   ┌────────────────────┐&lt;br /&gt;
   │ x86_64          │   │ Turing (TU104)   │   │ 570.144 (anchor)   │&lt;br /&gt;
   │ aarch64 (Grace) │   │ Ampere / Ada     │   │ newer families     │&lt;br /&gt;
   │ GB10-class      │   │ Hopper / datac.  │   │ (gated, pending    │&lt;br /&gt;
   └────────┬────────┘   └────────┬─────────┘   │  review)           │&lt;br /&gt;
            │                     │             └─────────┬──────────┘&lt;br /&gt;
            └──────────┬──────────┴───────────────────────┘&lt;br /&gt;
                       ▼&lt;br /&gt;
        one combination = hardware profile + version profile&lt;br /&gt;
                       ▼&lt;br /&gt;
        evaluation ladder + evidence  →  matrix entry:&lt;br /&gt;
        &amp;quot;hardware X + driver Y + firmware Z, tested at rung R on date D&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The configuration surface lives in &amp;lt;code&amp;gt;config/&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;config/hardware/&amp;amp;lt;arch&amp;amp;gt;.yaml&amp;lt;/code&amp;gt; (PCI IDs, BARs, memory geometry, engine lists) and &amp;lt;code&amp;gt;config/versions/&amp;amp;lt;driver&amp;amp;gt;.yaml&amp;lt;/code&amp;gt; (RPC/control inventories, capability tables).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''These files are design targets, not live configuration.''' No code reads them today: selection is compile-time and the module is built for the TU104 profile. Treating the YAML surface as authoritative — or claiming &amp;quot;configuration-driven portability&amp;quot; — is aspirational until the profiles are wired into the module's load path. A profile is the ''unit of support''; what is missing is the code that reads the profile files, not the schema.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 6. Adding a new combination ==&lt;br /&gt;
&lt;br /&gt;
'''New GPU / hardware profile.'''&lt;br /&gt;
&lt;br /&gt;
# Create a hardware profile: PCI IDs, BAR layout and sizes, memory geometry (FB size, BAR windows), engine inventory, interrupt topology, and the register values the guest driver validates during probe.&lt;br /&gt;
# Run the five-rung evaluation ladder ([https://git.vgpu.io/open-iov/blob/master/docs/05-operations/01-performance-correctness-security.md &amp;lt;code&amp;gt;../docs/05-operations/01-performance-correctness-security.md&amp;lt;/code&amp;gt;]).&lt;br /&gt;
# Record the differences; prefer configuration over code.&lt;br /&gt;
# Publish the profile, the evidence, and any workarounds.&lt;br /&gt;
&lt;br /&gt;
Firmware-side analysis uses the risc-v-gsp-rm-debugger ([[risc-v-gsp-rm-debugger|&amp;lt;code&amp;gt;Riscv-GSP-RM-Debugger.md&amp;lt;/code&amp;gt;]]): first-touch probes and per-pair comparisons classify each difference as profile data or logic before any profile change lands.&lt;br /&gt;
&lt;br /&gt;
'''New firmware version.''' Images are versioned under &amp;lt;code&amp;gt;firmware/&amp;amp;lt;SERIES&amp;amp;gt;-GSP/&amp;amp;lt;VERSION&amp;amp;gt;/&amp;lt;/code&amp;gt; with signatures and analysis artifacts; the work is capture, inventory diff, decode against that version's reference, then configuration/handlers and a re-run of the ladder.&lt;br /&gt;
&lt;br /&gt;
'''New driver version.''' Run the trace, diff the RPC/control inventory, add version-keyed handlers, re-run the ladder. Newer driver/firmware families are gated pending review before any work starts.&lt;br /&gt;
&lt;br /&gt;
'''Evidence expectations.''' A combination is entered in the matrix only with the profile fields recorded; the firmware/device pairing verified by hash and version string; every first-touch difference explained as profile or logic; per-pair comparison results with session hashes; the metric table with its reference-capture method and stated fidelity limits; and a supervised physical validation for the support claim. &amp;quot;Tested and documented&amp;quot; is literal: an untested or simulator-only combination stays '''Target''' or '''Experimental'''.&lt;br /&gt;
&lt;br /&gt;
== 7. Anchor versions and engine-list portability ==&lt;br /&gt;
&lt;br /&gt;
The anchor is guest CUDA driver (&amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt;) '''570.144''' with GSP firmware '''570.144'''; the host oracle is &amp;lt;code&amp;gt;libcuda&amp;lt;/code&amp;gt; '''570.211.01''' with CUDA toolkit '''12.0'''. The versioned surface is the RM ioctl/class/control interface the userspace driver issues — not a stable public API; see [[CUDA Userspace Driver|&amp;lt;code&amp;gt;CUDA-Userspace-Driver.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
The engine inventory and its class-list filtering are per-architecture, per-driver data. An earlier gap was concrete: a missing async copy engine blocked context creation until the inventory was completed — which is why it belongs in the hardware profile, validated against the host oracle.&lt;br /&gt;
&lt;br /&gt;
== 8. Known portability risks ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Risk&lt;br /&gt;
! Mitigation&lt;br /&gt;
|-&lt;br /&gt;
| Page-size/cache-attribute differences on aarch64&lt;br /&gt;
| keep the memory model abstract; test on Grace early&lt;br /&gt;
|-&lt;br /&gt;
| Windows driver ROM/VBIOS expectations&lt;br /&gt;
| explicit ROM/VBIOS provisioning in the device profile; measured bring-up&lt;br /&gt;
|-&lt;br /&gt;
| Xen interrupt/memory interfaces differ&lt;br /&gt;
| narrow transport interface + Xen backend plan&lt;br /&gt;
|-&lt;br /&gt;
| Vendor ROMs and laptop firmware variants (GB10/Surface)&lt;br /&gt;
| per-device overrides in the profile system&lt;br /&gt;
|-&lt;br /&gt;
| Driver-family drift (580 and newer)&lt;br /&gt;
| version-keyed handlers; matrix-driven testing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 9. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/06-portability/hardware-software-matrix.md &amp;lt;code&amp;gt;../docs/06-portability/hardware-software-matrix.md&amp;lt;/code&amp;gt;] — canonical matrix: ladder, status, procedures; the validation process behind every support claim is in [https://git.vgpu.io/open-iov/blob/master/docs/06-portability/03-device-validation-and-porting-sequence.md &amp;lt;code&amp;gt;../docs/06-portability/03-device-validation-and-porting-sequence.md&amp;lt;/code&amp;gt;].&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/05-operations/01-performance-correctness-security.md &amp;lt;code&amp;gt;../docs/05-operations/01-performance-correctness-security.md&amp;lt;/code&amp;gt;] — the five-rung evaluation ladder and evidence rules.&lt;br /&gt;
* [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] and [[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]] — current status and component map.&lt;br /&gt;
* [[risc-v-gsp-rm-debugger|&amp;lt;code&amp;gt;Riscv-GSP-RM-Debugger.md&amp;lt;/code&amp;gt;]] — firmware-side portability analysis.&lt;br /&gt;
* [[HAAEEP and Collaboration|&amp;lt;code&amp;gt;HAAEEP-and-Collaboration.md&amp;lt;/code&amp;gt;]] — the edge use case and collaboration models.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
	<entry>
		<id>https://open-iov.org/index.php?title=HAAEEP_and_Collaboration&amp;diff=23945</id>
		<title>HAAEEP and Collaboration</title>
		<link rel="alternate" type="text/html" href="https://open-iov.org/index.php?title=HAAEEP_and_Collaboration&amp;diff=23945"/>
		<updated>2026-10-12T04:29:47Z</updated>

		<summary type="html">&lt;p&gt;WikiBot: Carry the site-wide About/licensing message on every page (2026-10-12)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{About message}}&lt;br /&gt;
&lt;br /&gt;
= HAAEEP and Collaboration =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;'''Companion summary — target architecture.''' This page condenses [https://git.vgpu.io/open-iov/blob/master/docs/08-ecosystem/haaeep-and-collaboration.md &amp;lt;code&amp;gt;../docs/08-ecosystem/haaeep-and-collaboration.md&amp;lt;/code&amp;gt;], the canonical description of the '''High Assurance Agent Edge Environment Platform (HAAEEP)''': a target architecture that Open-IOV exists to enable, and the collaboration models around it. HAAEEP is a proposal and a roadmap, not a shipped product. When this page and the docs tree disagree, the docs tree wins. Front door: [https://git.vgpu.io/open-iov/blob/master/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;].&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status: 2026-10-12, tree &amp;lt;code&amp;gt;master @ 2f066727&amp;lt;/code&amp;gt;. Tags: &amp;lt;code&amp;gt;[proposal]&amp;lt;/code&amp;gt; architecture and roadmap; &amp;lt;code&amp;gt;[target]&amp;lt;/code&amp;gt; milestone to reach; &amp;lt;code&amp;gt;[goal]&amp;lt;/code&amp;gt; end state; &amp;lt;code&amp;gt;[design]&amp;lt;/code&amp;gt; integration point designed, not built.&lt;br /&gt;
&lt;br /&gt;
== 1. What HAAEEP is ==&lt;br /&gt;
&lt;br /&gt;
An AI agent harness (Claude Code, OpenCode, or any future equivalent) is an untrusted, capability-constrained workload: it runs generated code, holds credentials, and talks to a model. In a ''cloud'' deployment its requests leave the device; in a ''secure edge'' deployment — a workstation, a kiosk, a vehicle, a medical or industrial system — they must not.&lt;br /&gt;
&lt;br /&gt;
HAAEEP is the platform shape for that edge deployment:&lt;br /&gt;
&lt;br /&gt;
* inference runs '''locally''', in its own VM, with the GPU;&lt;br /&gt;
* agents run in '''their own VMs''', without the GPU and without the weights;&lt;br /&gt;
* other functions (desktop, networking, storage) run in '''other VMs''', each isolated;&lt;br /&gt;
* the whole stack is '''attestable''', so remote parties can verify it;&lt;br /&gt;
* and nothing in the design requires the model server, the agent, or the GPU driver to be modified.&lt;br /&gt;
&lt;br /&gt;
Open-IOV is HAAEEP's GPU component. The broader motivation is in [https://git.vgpu.io/open-iov/blob/master/docs/01-orientation/02-the-ai-edge-and-ecosystem.md &amp;lt;code&amp;gt;../docs/01-orientation/02-the-ai-edge-and-ecosystem.md&amp;lt;/code&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
== 2. Architecture ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;┌──────────────────────────────────────────────────────────────────────────┐&lt;br /&gt;
│ EDGE DEVICE — one GPU, local inference only                              │&lt;br /&gt;
│                                                                          │&lt;br /&gt;
│  ┌─────────────────┐     ┌──────────────────┐    ┌───────────────────┐   │&lt;br /&gt;
│  │ Agent VM        │     │ Inference VM     │    │ Infrastructure    │   │&lt;br /&gt;
│  │ capability-     │────▶│ vLLM / SGLang    │    │ desktop, net,     │   │&lt;br /&gt;
│  │ constrained     │ API │ owns GPU via     │    │ storage VMs       │   │&lt;br /&gt;
│  │ no GPU          │     │ Open-IOV mdev or │    │ optional GPU accel│   │&lt;br /&gt;
│  │                 │     │ xen-pci + relay  │    │ via Open-IOV      │   │&lt;br /&gt;
│  └─────────────────┘     └────────┬─────────┘    └───────────────────┘   │&lt;br /&gt;
│                                   │                                      │&lt;br /&gt;
│  ┌────────────────────────────────┴───────────────────────────────────┐  │&lt;br /&gt;
│  │ Hypervisor: KVM / Xen + Argo/OpenXT / Qubes OS Air                 │  │&lt;br /&gt;
│  │  • Flask-XSM / HMX mandatory access control between VMs            │  │&lt;br /&gt;
│  │  • TrenchBoot measured boot: firmware → hypervisor → OS            │  │&lt;br /&gt;
│  │  • Open-IOV: per-VM virtual GPUs, IOMMU-enforced isolation         │  │&lt;br /&gt;
│  └────────────────────────────────────────────────────────────────────┘  │&lt;br /&gt;
└──────────────────────────────────────────────────────────────────────────┘&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Roles and trust ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Component&lt;br /&gt;
! Trust&lt;br /&gt;
! Why&lt;br /&gt;
|-&lt;br /&gt;
| Agent VM&lt;br /&gt;
| untrusted&lt;br /&gt;
| runs generated code; may be compromised&lt;br /&gt;
|-&lt;br /&gt;
| Inference VM&lt;br /&gt;
| high (holds weights)&lt;br /&gt;
| isolated from agents by MAC and by device virtualization&lt;br /&gt;
|-&lt;br /&gt;
| GPU-owning VM (optional)&lt;br /&gt;
| high&lt;br /&gt;
| owns the physical device; can serve others through Open-IOV&lt;br /&gt;
|-&lt;br /&gt;
| Infrastructure VMs&lt;br /&gt;
| medium&lt;br /&gt;
| GPU acceleration optional; no access to weights&lt;br /&gt;
|-&lt;br /&gt;
| Hypervisor&lt;br /&gt;
| TCB&lt;br /&gt;
| enforced by the platform (Argo/OpenXT/Qubes)&lt;br /&gt;
|-&lt;br /&gt;
| Open-IOV device&lt;br /&gt;
| TCB-adjacent&lt;br /&gt;
| must fail closed; audited (see the security doc)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 4. Data flow ==&lt;br /&gt;
&lt;br /&gt;
# An agent VM issues an API call to the inference VM over an internal, MAC-controlled channel.&lt;br /&gt;
# The inference VM's vLLM/SGLang (unchanged) serves the request with the GPU, using its KV-cache plugins (also unchanged).&lt;br /&gt;
# No request ever leaves the device: the platform's network policy forbids external inference endpoints by construction.&lt;br /&gt;
&lt;br /&gt;
'''Optional topology — GPU relay domain.''' Where the platform prefers it (Xen with &amp;lt;code&amp;gt;xen-pci&amp;lt;/code&amp;gt;), one domain owns the physical GPU and relays acceleration to other domains through Open-IOV: the process running the model is isolated from the domain that owns the silicon, and agents are isolated from both.&lt;br /&gt;
&lt;br /&gt;
== 5. Why Open-IOV fits ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Alternative&lt;br /&gt;
! Why it is not enough&lt;br /&gt;
|-&lt;br /&gt;
| Discrete passthrough&lt;br /&gt;
| gives the GPU to exactly one VM; HAAEEP needs the GPU in the inference VM ''and'' optional acceleration elsewhere&lt;br /&gt;
|-&lt;br /&gt;
| Process-level sharing (host CUDA with containers)&lt;br /&gt;
| no VM-level isolation, which is the whole point of the platform&lt;br /&gt;
|-&lt;br /&gt;
| Proprietary vGPU&lt;br /&gt;
| cannot build a sovereign, auditable, redistributable edge platform on a licensed host stack you cannot inspect or modify&lt;br /&gt;
|-&lt;br /&gt;
| Software GPU emulation&lt;br /&gt;
| cannot run models usefully&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Open-IOV is the component in this design that ''must'' be open, permissively licensed and version-durable — so it is the component we are building. Its isolation model is described in [[GMMU Multi-Tenant Protection|&amp;lt;code&amp;gt;GMMU-Multi-Tenant-Protection.md&amp;lt;/code&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
== 6. Roadmap (proposal) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Milestone&lt;br /&gt;
! Depends on&lt;br /&gt;
|-&lt;br /&gt;
| CUDA execution in a guest (rung 3)&lt;br /&gt;
| rung 2 (runtime start) is green; CE-class work is forwarded with release and fault relay in place (default off); for GR the guest launch reaches the front-end but no grid has dispatched yet — the frontier is tracked in [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]]&lt;br /&gt;
|-&lt;br /&gt;
| Two-VM coexistence (inference + agent) with isolation&lt;br /&gt;
| Open-IOV multi-tenancy + platform MAC&lt;br /&gt;
|-&lt;br /&gt;
| Xen/OpenXT or Qubes Air variant&lt;br /&gt;
| Open-IOV transport backends&lt;br /&gt;
|-&lt;br /&gt;
| Attested boot-to-inference chain&lt;br /&gt;
| TrenchBoot integration&lt;br /&gt;
|-&lt;br /&gt;
| Published reference platform (scripts, docs)&lt;br /&gt;
| all of the above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each milestone is documented as it lands, with the same evidence discipline as the rest of the project. Nothing in this table is claimed today: it is the proposal.&lt;br /&gt;
&lt;br /&gt;
== 7. Collaboration models ==&lt;br /&gt;
&lt;br /&gt;
'''Open source projects.''' Adopt the code under BSD-3-Clause (kernel modules are GPL-2.0 — see [https://git.vgpu.io/open-iov/blob/master/docs/09-reference/legal-and-licensing.md &amp;lt;code&amp;gt;../docs/09-reference/legal-and-licensing.md&amp;lt;/code&amp;gt;]). We treat interface requirements as design inputs (transports, IRQ models, memory interfaces), provide the transport abstraction rather than asking for forks, and test against partner platforms in the matrix.&lt;br /&gt;
&lt;br /&gt;
'''Commercial partners.''' Welcome, with no license fee: ship Open-IOV in products and differentiate above it; sponsor support for specific hardware/driver versions; co-develop under the same permissive terms.&lt;br /&gt;
&lt;br /&gt;
'''Hardware vendors.''' Nothing is required. The goal is that new hardware works through configuration and measurement; if you want to accelerate support, share hardware and traces, and we publish what we learn.&lt;br /&gt;
&lt;br /&gt;
'''Security researchers.''' The emulation's attack surface is small and documented. Break it. Findings and fixes are published, with credit.&lt;br /&gt;
&lt;br /&gt;
== 8. Cross-project notes ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Project&lt;br /&gt;
! Relationship&lt;br /&gt;
|-&lt;br /&gt;
| '''Qubes OS Air'''&lt;br /&gt;
| compartmentalization on modern hardware; Open-IOV makes GPU acceleration usable per compartment (especially AI workloads)&lt;br /&gt;
|-&lt;br /&gt;
| '''TrenchBoot'''&lt;br /&gt;
| measured/attested boot; combined, the platform can attest the inference path&lt;br /&gt;
|-&lt;br /&gt;
| '''Argo / OpenXT'''&lt;br /&gt;
| hypervisor-mediated exchange (HMX) and Flask-XSM MAC; Open-IOV respects and complements that policy&lt;br /&gt;
|-&lt;br /&gt;
| '''KVM/VFIO gaming'''&lt;br /&gt;
| established the fast-passthrough pattern; Open-IOV serves users who need ''multiple'' VMs or cannot dedicate the GPU&lt;br /&gt;
|-&lt;br /&gt;
| '''vLLM / SGLang'''&lt;br /&gt;
| remain the inference answer; Open-IOV isolates them without changing them; KV-cache plugins keep working&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 9. How to help ==&lt;br /&gt;
&lt;br /&gt;
* '''Platform builders''': bring your hypervisor; tell us the transport you need.&lt;br /&gt;
* '''Security engineers''': review the isolation model and the debug surface.&lt;br /&gt;
* '''AI-infrastructure engineers''': define the reference HAAEEP deployment with us (model server, KV cache, agent harness).&lt;br /&gt;
* '''Everyone''': run the evaluation ladder on your hardware and send the evidence.&lt;br /&gt;
&lt;br /&gt;
Contact and participation channels are in [https://git.vgpu.io/open-iov/blob/master/docs/README.md &amp;lt;code&amp;gt;../docs/README.md&amp;lt;/code&amp;gt;] §6 &amp;quot;How to get involved&amp;quot;. We would rather have a hundred partners than a hundred forks.&lt;br /&gt;
&lt;br /&gt;
== 10. Related documentation ==&lt;br /&gt;
&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/08-ecosystem/haaeep-and-collaboration.md &amp;lt;code&amp;gt;../docs/08-ecosystem/haaeep-and-collaboration.md&amp;lt;/code&amp;gt;] — canonical HAAEEP architecture, roadmap and collaboration models.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/01-orientation/02-the-ai-edge-and-ecosystem.md &amp;lt;code&amp;gt;../docs/01-orientation/02-the-ai-edge-and-ecosystem.md&amp;lt;/code&amp;gt;] — the AI-edge motivation and ecosystem stance.&lt;br /&gt;
* [https://git.vgpu.io/open-iov/blob/master/docs/05-operations/01-performance-correctness-security.md &amp;lt;code&amp;gt;../docs/05-operations/01-performance-correctness-security.md&amp;lt;/code&amp;gt;] — the evaluation ladder behind every milestone.&lt;br /&gt;
* [[Project Status|&amp;lt;code&amp;gt;Project-Status.md&amp;lt;/code&amp;gt;]] and [[System Overview|&amp;lt;code&amp;gt;System-Overview.md&amp;lt;/code&amp;gt;]] — current status and component map.&lt;br /&gt;
* [[The Execution Frontier|&amp;lt;code&amp;gt;Execution-Frontier.md&amp;lt;/code&amp;gt;]] and [[Physical GPU Backend and Guest Wiring|&amp;lt;code&amp;gt;Physical-GPU-Backend.md&amp;lt;/code&amp;gt;]] — the GR frontier and how work reaches real hardware.&lt;br /&gt;
* [[Hardware and Software Matrix|&amp;lt;code&amp;gt;Hardware-Software-Matrix.md&amp;lt;/code&amp;gt;]] — what runs where, and how support is added.&lt;/div&gt;</summary>
		<author><name>WikiBot</name></author>
	</entry>
</feed>