Difference between revisions of "RPC Message Format"

From Open-IOV
Jump to navigation Jump to search
(Remove unpaired blockquote tags left by reference cleanup)
 
m (Fix repository links: point to the cgit tree URLs)
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
<span id="gsp-rpc-message-format-specification"></span>
{{About message}}
 
= GSP RPC Message Format Specification =
= GSP RPC Message Format Specification =


<span id="overview"></span>
<blockquote>'''Historical document — superseded.''' This page describes the legacy BAR0 mailbox RPC model: the 64-byte <code>GSPR</code> 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 <code>0x43505256</code>, header version <code>0x03000000</code>); functions are a flat enum (<code>SET_GUEST_SYSTEM_INFO</code> 1, <code>FREE</code> 10, <code>GET_GSP_STATIC_INFO</code> 65, <code>GSP_RM_CONTROL</code> 76, <code>GSP_RM_ALLOC</code> 103, ...). Canonical documentation: [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/03-gsp-and-gsp-rm.md <code>../docs/03-architecture/03-gsp-and-gsp-rm.md</code>] and [https://git.vgpu.io/open-iov.git/tree/docs/03-architecture/06-host-module-and-hybrid-model.md <code>../docs/03-architecture/06-host-module-and-hybrid-model.md</code>].</blockquote>
 
== Overview ==
== Overview ==


Line 10: Line 12:
* '''Secondary''' (0x04ED39DC): Branch-based dispatch for all 11 types
* '''Secondary''' (0x04ED39DC): Branch-based dispatch for all 11 types


<span id="primary-dispatcher-call-convention"></span>
== Primary Dispatcher Call Convention ==
== Primary Dispatcher Call Convention ==


<span id="entry-point"></span>
=== Entry Point ===
=== Entry Point ===


Line 26: Line 26:
     uint8_t  *out_c        // param_8: Echoes flags_c
     uint8_t  *out_c        // param_8: Echoes flags_c
) -&gt; int64_t</pre>
) -&gt; int64_t</pre>
<span id="rpc-type-to-sub-command-mapping"></span>
 
=== RPC Type to Sub-Command Mapping ===
=== RPC Type to Sub-Command Mapping ===


The primary dispatcher validates RPC type, then indexes into the 32-entry jump table at '''0x057A3AD8'''.
The primary dispatcher validates RPC type, then indexes into the 32-entry jump table at '''0x057A3AD8'''.
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 45: Line 46:
| FREE
| FREE
| 0-31
| 0-31
|
|  
|-
|-
| 0x03
| 0x03
Line 98: Line 99:
|}
|}


<span id="sub-command-descriptor-returned-by-jump-table-handlers"></span>
=== Sub-Command Descriptor (Returned by Jump Table Handlers) ===
=== Sub-Command Descriptor (Returned by Jump Table Handlers) ===


Each sub-command handler at the jump table returns:
Each sub-command handler at the jump table returns:


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint32_t subcmd_id;    // Constant ID (e.g., 0x10, 0x14, 0x40)
     uint32_t subcmd_id;    // Constant ID (e.g., 0x10, 0x14, 0x40)
     uint8_t  echo_flags_b;  // Copy of input flags_b
     uint8_t  echo_flags_b;  // Copy of input flags_b
     uint8_t  echo_flags_a;  // Copy of input flags_a
     uint8_t  echo_flags_a;  // Copy of input flags_a
     uint8_t  echo_flags_c;  // Copy of input flags_c
     uint8_t  echo_flags_c;  // Copy of input flags_c
} __attribute__((packed)) subcmd_descriptor_t;</syntaxhighlight>
} __attribute__((packed)) subcmd_descriptor_t;</pre>
 
'''Example: Subcmd 3 (0x057A1BCC)'''
'''Example: Subcmd 3 (0x057A1BCC)'''


<syntaxhighlight lang="c">// Returns ID = 0x10
<pre>// Returns ID = 0x10
*out_subcmd_id = 0x10;
*out_subcmd_id = 0x10;
*out_a = flags_b;
*out_a = flags_b;
*out_b = flags_a;
*out_b = flags_a;
*out_c = flags_c;
*out_c = flags_c;
return 0;</syntaxhighlight>
return 0;</pre>
 
'''Example: Subcmd 0 (0x057A1DB4)'''
'''Example: Subcmd 0 (0x057A1DB4)'''


<syntaxhighlight lang="c">// Returns ID = 0x40
<pre>// Returns ID = 0x40
*out_subcmd_id = 0x40;
*out_subcmd_id = 0x40;
*out_a = flags_b;
*out_a = flags_b;
*out_b = flags_a;
*out_b = flags_a;
*out_c = flags_c;
*out_c = flags_c;
return 0;</syntaxhighlight>
return 0;</pre>
<span id="secondary-dispatcher-call-convention"></span>
 
== Secondary Dispatcher Call Convention ==
== Secondary Dispatcher Call Convention ==


<span id="entry-point-1"></span>
=== Entry Point ===
=== Entry Point ===


<pre>FUN_ram_04ed39dc(rpc_message_t *msg) -&gt; int64_t</pre>
<pre>FUN_ram_04ed39dc(rpc_message_t *msg) -&gt; int64_t</pre>
<span id="message-structure-inferred"></span>
 
=== Message Structure (Inferred) ===
=== Message Structure (Inferred) ===


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint32_t rpc_type;      // 0x01-0x0B
     uint32_t rpc_type;      // 0x01-0x0B
     uint32_t sub_type;      // Sub-operation code
     uint32_t sub_type;      // Sub-operation code
Line 144: Line 145:
     uint32_t sequence;      // Sequence number
     uint32_t sequence;      // Sequence number
     uint32_t reserved;
     uint32_t reserved;
} __attribute__((packed)) rpc_message_t;</syntaxhighlight>
} __attribute__((packed)) rpc_message_t;</pre>
<span id="branch-based-dispatch"></span>
 
=== Branch-Based Dispatch ===
=== Branch-Based Dispatch ===


Secondary dispatcher uses <code>bgeu</code>/<code>bltu</code> branches on <code>rpc_type</code> register:
Secondary dispatcher uses <code>bgeu</code>/<code>bltu</code> branches on <code>rpc_type</code> register:


<pre class="assembly"># Pseudocode
<pre># Pseudocode
if (rpc_type &gt;= 0x0C) goto error;
if (rpc_type &gt;= 0x0C) goto error;
switch(rpc_type):
switch(rpc_type):
Line 161: Line 162:
   case 0x09: call NOTIFY_handler_A;
   case 0x09: call NOTIFY_handler_A;
   case 0x0A: call BAR_TRAP_handler (0x057675B7);</pre>
   case 0x0A: call BAR_TRAP_handler (0x057675B7);</pre>
<span id="rpc-specific-payloads"></span>
 
== RPC-Specific Payloads ==
== RPC-Specific Payloads ==


<span id="alloc-0x01---via-0x057e94ec"></span>
=== ALLOC (0x01) - Via 0x057E94EC ===
=== ALLOC (0x01) - Via 0x057E94EC ===


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint64_t size;          // Allocation size in bytes
     uint64_t size;          // Allocation size in bytes
     uint32_t type;          // Memory type (VRAM, sysmem, etc.)
     uint32_t type;          // Memory type (VRAM, sysmem, etc.)
Line 179: Line 179:
     uint64_t *out_va;      // Output: mapped virtual address
     uint64_t *out_va;      // Output: mapped virtual address
     uint64_t *out_pa;      // Output: physical address
     uint64_t *out_pa;      // Output: physical address
} alloc_payload_t;</syntaxhighlight>
} alloc_payload_t;</pre>
<span id="map-0x03---handlers-0x05766ab7--0x05778a37"></span>
 
=== MAP (0x03) - Handlers 0x05766AB7 / 0x05778A37 ===
=== MAP (0x03) - Handlers 0x05766AB7 / 0x05778A37 ===


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint64_t handle;        // Allocation handle from ALLOC
     uint64_t handle;        // Allocation handle from ALLOC
     uint64_t va;            // Target virtual address
     uint64_t va;            // Target virtual address
Line 191: Line 191:
     uint32_t vf_id;        // Target VF
     uint32_t vf_id;        // Target VF
     uint32_t reserved;
     uint32_t reserved;
} map_payload_t;</syntaxhighlight>
} map_payload_t;</pre>
<span id="pin-0x05---handler-0x04ed34b8"></span>
 
=== PIN (0x05) - Handler 0x04ED34B8 ===
=== PIN (0x05) - Handler 0x04ED34B8 ===


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint64_t handle;        // Allocation handle
     uint64_t handle;        // Allocation handle
     uint64_t offset;        // Offset within allocation
     uint64_t offset;        // Offset within allocation
Line 202: Line 202:
     uint32_t flags;        // PIN_WRITE, PIN_READ, PIN_LONGTERM
     uint32_t flags;        // PIN_WRITE, PIN_READ, PIN_LONGTERM
     uint64_t *out_dma_addr; // Output: DMA address for device
     uint64_t *out_dma_addr; // Output: DMA address for device
} pin_payload_t;</syntaxhighlight>
} pin_payload_t;</pre>
<span id="schedule-0x07---via-0x051efbf4--0x05767f37"></span>
 
=== SCHEDULE (0x07) - Via 0x051EFBF4 / 0x05767F37 ===
=== SCHEDULE (0x07) - Via 0x051EFBF4 / 0x05767F37 ===


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint32_t vf_id;        // VF to schedule
     uint32_t vf_id;        // VF to schedule
     uint32_t priority;      // Scheduling priority
     uint32_t priority;      // Scheduling priority
Line 212: Line 212:
     uint32_t flags;        // PREEMPTIBLE, REALTIME, etc.
     uint32_t flags;        // PREEMPTIBLE, REALTIME, etc.
     uint32_t reserved;
     uint32_t reserved;
} schedule_payload_t;</syntaxhighlight>
} schedule_payload_t;</pre>
<span id="bar_trap-0x0a---handler-0x04cb8188"></span>
 
=== BAR_TRAP (0x0A) - Handler 0x04CB8188 ===
=== BAR_TRAP (0x0A) - Handler 0x04CB8188 ===


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint32_t bar_index;    // BAR number (0-5)
     uint32_t bar_index;    // BAR number (0-5)
     uint32_t trap_type;    // READ, WRITE, ATOMIC
     uint32_t trap_type;    // READ, WRITE, ATOMIC
Line 224: Line 224:
     uint32_t vf_id;        // Trapping VF
     uint32_t vf_id;        // Trapping VF
     uint64_t *out_value;    // Output: read value
     uint64_t *out_value;    // Output: read value
} bar_trap_payload_t;</syntaxhighlight>
} bar_trap_payload_t;</pre>
<span id="migrate-0x0b---dual-jump-tables"></span>
 
=== MIGRATE (0x0B) - Dual Jump Tables ===
=== MIGRATE (0x0B) - Dual Jump Tables ===


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint32_t phase;        // 0=prepare, 1=transfer, 2=commit, 3=cleanup
     uint32_t phase;        // 0=prepare, 1=transfer, 2=commit, 3=cleanup
     uint32_t subcmd;        // Sub-command index (0-15 for each table)
     uint32_t subcmd;        // Sub-command index (0-15 for each table)
Line 237: Line 237:
     uint32_t flags;        // LIVE, POSTCOPY, etc.
     uint32_t flags;        // LIVE, POSTCOPY, etc.
     uint32_t reserved;
     uint32_t reserved;
} migrate_payload_t;</syntaxhighlight>
} migrate_payload_t;</pre>
<span id="wire-format-host--gsp"></span>
 
== Wire Format (Host → GSP) ==
== Wire Format (Host → GSP) ==


'''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.
<blockquote>'''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.</blockquote>


<span id="message-header-64-bytes"></span>
=== Message Header (64 bytes) ===
=== Message Header (64 bytes) ===


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint32_t magic;        // 0x47535052 ("GSPR")
     uint32_t magic;        // 0x47535052 ("GSPR")
     uint32_t version;      // Protocol version (1)
     uint32_t version;      // Protocol version (1)
Line 256: Line 255:
     uint64_t correlation_id;// For async matching
     uint64_t correlation_id;// For async matching
     uint64_t reserved[3];  // Padding to 64 bytes
     uint64_t reserved[3];  // Padding to 64 bytes
} __attribute__((packed)) rpc_header_t;</syntaxhighlight>
} __attribute__((packed)) rpc_header_t;</pre>
<span id="complete-message"></span>
 
=== Complete Message ===
=== Complete Message ===


Line 267: Line 266:
| padding to 256B  |  (alignment)
| padding to 256B  |  (alignment)
+------------------+</pre>
+------------------+</pre>
<span id="response-format"></span>
 
== Response Format ==
== Response Format ==


<span id="synchronous-response"></span>
=== Synchronous Response ===
=== Synchronous Response ===


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     int64_t status;        // 0 = success, negative = error
     int64_t status;        // 0 = success, negative = error
     uint32_t rpc_type;      // Echo of request
     uint32_t rpc_type;      // Echo of request
Line 280: Line 278:
     uint32_t payload_size;  // Response payload size
     uint32_t payload_size;  // Response payload size
     uint32_t reserved;
     uint32_t reserved;
} __attribute__((packed)) rpc_response_header_t;</syntaxhighlight>
} __attribute__((packed)) rpc_response_header_t;</pre>
<span id="error-codes"></span>
 
=== Error Codes ===
=== Error Codes ===


Line 359: Line 357:
|}
|}


<span id="kernel-client-implementation"></span>
== Kernel Client Implementation ==
== Kernel Client Implementation ==


<span id="message-builder"></span>
=== Message Builder ===
=== Message Builder ===


<syntaxhighlight lang="c">static int gsp_rpc_send(gsp_client_t *client, uint32_t rpc_type,  
<pre>static int gsp_rpc_send(gsp_client_t *client, uint32_t rpc_type,  
                         void *payload, size_t payload_size,
                         void *payload, size_t payload_size,
                         void *response, size_t *response_size) {
                         void *response, size_t *response_size) {
     rpc_header_t hdr = {.magic = 0x47535052,.version = 1,.rpc_type = rpc_type,.sequence = atomic_inc(&client->seq),.timestamp_ns = ktime_get_ns,.payload_size = payload_size,.flags = MSG_SYNC,
     rpc_header_t hdr = {
        .magic = 0x47535052,
        .version = 1,
        .rpc_type = rpc_type,
        .sequence = atomic_inc(&amp;client-&gt;seq),
        .timestamp_ns = ktime_get_ns(),
        .payload_size = payload_size,
        .flags = MSG_SYNC,
     };
     };
      
      
     // Build complete message
     // Build complete message
     uint8_t msg[256];
     uint8_t msg[256];
     memcpy(msg, &hdr, sizeof(hdr));
     memcpy(msg, &amp;hdr, sizeof(hdr));
     memcpy(msg + 64, payload, payload_size);
     memcpy(msg + 64, payload, payload_size);
      
      
     // Submit to GSP doorbell
     // Submit to GSP doorbell
     return gsp_doorbell_ring(client->gsp, msg, sizeof(msg));
     return gsp_doorbell_ring(client-&gt;gsp, msg, sizeof(msg));
}</syntaxhighlight>
}</pre>
<span id="doorbell-mechanism"></span>
 
=== Doorbell Mechanism ===
=== Doorbell Mechanism ===


<syntaxhighlight lang="c">// GSP doorbell register (PCIe BAR0 + offset)
<pre>// GSP doorbell register (PCIe BAR0 + offset)
#define GSP_DOORBELL_OFFSET  0x1000
#define GSP_DOORBELL_OFFSET  0x1000


Line 388: Line 391:
     // Copy message to shared memory ring
     // Copy message to shared memory ring
     // Ring GSP doorbell
     // Ring GSP doorbell
     writel(1, gsp->bar0 + GSP_DOORBELL_OFFSET);
     writel(1, gsp-&gt;bar0 + GSP_DOORBELL_OFFSET);
}</syntaxhighlight>
}</pre>
<span id="async-completion"></span>
 
== Async Completion ==
== Async Completion ==


<span id="notification-mechanism"></span>
=== Notification Mechanism ===
=== Notification Mechanism ===


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint32_t rpc_type;
     uint32_t rpc_type;
     uint32_t sequence;
     uint32_t sequence;
Line 405: Line 407:
} async_completion_t;
} async_completion_t;


// Delivered via MSI-X or GSP notification queue</syntaxhighlight>
// Delivered via MSI-X or GSP notification queue</pre>


-----
----


<span id="reference"></span>
== Reference ==
== Reference ==



Latest revision as of 04:41, 12 October 2026

An absence of critical technical documentation has historically slowed growth and adoption of developer ecosystems for GPU virtualization.

This CC-BY-4.0 licensed content can either be used with attribution, or used as inspiration for new documentation, created by GPU vendors for public commercial distribution as developer documentation.

Where possible, this documentation will clearly label dates and versions of observed-but-not-guaranteed behaviour vs. vendor-documented stable interfaces/behaviour with guarantees of forward or backward compatibility.

GSP RPC Message Format Specification

Historical document — superseded. This page describes the legacy BAR0 mailbox RPC model: the 64-byte GSPR 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 0x43505256, header version 0x03000000); functions are a flat enum (SET_GUEST_SYSTEM_INFO 1, FREE 10, GET_GSP_STATIC_INFO 65, GSP_RM_CONTROL 76, GSP_RM_ALLOC 103, ...). Canonical documentation: ../docs/03-architecture/03-gsp-and-gsp-rm.md and ../docs/03-architecture/06-host-module-and-hybrid-model.md.

Overview

The GSP firmware uses a dispatcher-based RPC system with two dispatchers:

  • Primary (0x057A1AC0): ALLOC, FREE, MAP, UNMAP, PIN, UNPIN, SCHEDULE, YIELD, NOTIFY, BAR_TRAP, MIGRATE, DEBUG
  • Secondary (0x04ED39DC): Branch-based dispatch for all 11 types

Primary Dispatcher Call Convention

Entry Point

FUN_ram_057a1ac0(
    uint32_t rpc_type,      // param_1: RPC type (0x01-0x0C)
    uint8_t  flags_a,       // param_2
    uint8_t  flags_b,       // param_3
    uint8_t  flags_c,       // param_4
    uint32_t *out_subcmd_id,// param_5: Returns sub-command ID
    uint8_t  *out_a,        // param_6: Echoes flags_b
    uint8_t  *out_b,        // param_7: Echoes flags_a
    uint8_t  *out_c         // param_8: Echoes flags_c
) -> int64_t

RPC Type to Sub-Command Mapping

The primary dispatcher validates RPC type, then indexes into the 32-entry jump table at 0x057A3AD8.

RPC Type Name Subcmd Range Notes
0x01 ALLOC 0-31 Uses 0x057E94EC main
0x02 FREE 0-31
0x03 MAP — Uses secondary dispatcher
0x04 UNMAP 0-31 Primary + secondary
0x05 PIN — Uses secondary dispatcher
0x06 UNPIN — Uses secondary dispatcher
0x07 SCHEDULE 0-31 Uses 0x051EFBF4 main
0x08 YIELD — Uses secondary dispatcher
0x09 NOTIFY — Uses secondary dispatcher
0x0A BAR_TRAP — Uses 0x04CB8188
0x0B MIGRATE 0-15 x2 Dual jump tables
0x0C DEBUG — Unimplemented

Sub-Command Descriptor (Returned by Jump Table Handlers)

Each sub-command handler at the jump table returns:

typedef struct {
    uint32_t subcmd_id;     // Constant ID (e.g., 0x10, 0x14, 0x40)
    uint8_t  echo_flags_b;  // Copy of input flags_b
    uint8_t  echo_flags_a;  // Copy of input flags_a
    uint8_t  echo_flags_c;  // Copy of input flags_c
} __attribute__((packed)) subcmd_descriptor_t;

Example: Subcmd 3 (0x057A1BCC)

// Returns ID = 0x10
*out_subcmd_id = 0x10;
*out_a = flags_b;
*out_b = flags_a;
*out_c = flags_c;
return 0;

Example: Subcmd 0 (0x057A1DB4)

// Returns ID = 0x40
*out_subcmd_id = 0x40;
*out_a = flags_b;
*out_b = flags_a;
*out_c = flags_c;
return 0;

Secondary Dispatcher Call Convention

Entry Point

FUN_ram_04ed39dc(rpc_message_t *msg) -> int64_t

Message Structure (Inferred)

typedef struct {
    uint32_t rpc_type;      // 0x01-0x0B
    uint32_t sub_type;      // Sub-operation code
    uint64_t payload_ptr;   // Pointer to RPC-specific payload
    uint32_t payload_size;  // Size of payload
    uint32_t flags;         // Control flags
    uint64_t context;       // Opaque context
    uint32_t sequence;      // Sequence number
    uint32_t reserved;
} __attribute__((packed)) rpc_message_t;

Branch-Based Dispatch

Secondary dispatcher uses bgeu/bltu branches on rpc_type register:

# Pseudocode
if (rpc_type >= 0x0C) goto error;
switch(rpc_type):
  case 0x03: call MAP_handler_A;
  case 0x04: call UNMAP_handler_A;
  case 0x05: call PIN_handler_A (0x04ED34B8);
  case 0x06: call UNPIN_handler_A;
  case 0x07: call SCHEDULE_handler_A;
  case 0x08: call YIELD_handler_A;
  case 0x09: call NOTIFY_handler_A;
  case 0x0A: call BAR_TRAP_handler (0x057675B7);

RPC-Specific Payloads

ALLOC (0x01) - Via 0x057E94EC

typedef struct {
    uint64_t size;          // Allocation size in bytes
    uint32_t type;          // Memory type (VRAM, sysmem, etc.)
    uint32_t alignment;     // Alignment requirement
    uint64_t va_hint;       // Virtual address hint
    uint32_t flags;         // CACHE_COHERENT, UNCACHED, etc.
    uint32_t pid;           // Process ID
    uint32_t vf_id;         // VF ID (for vGPU)
    uint32_t reserved;
    uint64_t *out_handle;   // Output: allocation handle
    uint64_t *out_va;       // Output: mapped virtual address
    uint64_t *out_pa;       // Output: physical address
} alloc_payload_t;

MAP (0x03) - Handlers 0x05766AB7 / 0x05778A37

typedef struct {
    uint64_t handle;        // Allocation handle from ALLOC
    uint64_t va;            // Target virtual address
    uint64_t size;          // Map size
    uint32_t prot;          // PROT_READ|PROT_WRITE|PROT_EXEC
    uint32_t flags;         // MAP_FIXED, MAP_SHARED, etc.
    uint32_t vf_id;         // Target VF
    uint32_t reserved;
} map_payload_t;

PIN (0x05) - Handler 0x04ED34B8

typedef struct {
    uint64_t handle;        // Allocation handle
    uint64_t offset;        // Offset within allocation
    uint64_t size;          // Size to pin
    uint32_t vf_id;         // Target VF
    uint32_t flags;         // PIN_WRITE, PIN_READ, PIN_LONGTERM
    uint64_t *out_dma_addr; // Output: DMA address for device
} pin_payload_t;

SCHEDULE (0x07) - Via 0x051EFBF4 / 0x05767F37

typedef struct {
    uint32_t vf_id;         // VF to schedule
    uint32_t priority;      // Scheduling priority
    uint64_t time_slice_ns; // Time slice in nanoseconds
    uint32_t flags;         // PREEMPTIBLE, REALTIME, etc.
    uint32_t reserved;
} schedule_payload_t;

BAR_TRAP (0x0A) - Handler 0x04CB8188

typedef struct {
    uint32_t bar_index;     // BAR number (0-5)
    uint32_t trap_type;     // READ, WRITE, ATOMIC
    uint64_t offset;        // Offset within BAR
    uint64_t value;         // Value for writes
    uint32_t size;          // Access size (1,2,4,8)
    uint32_t vf_id;         // Trapping VF
    uint64_t *out_value;    // Output: read value
} bar_trap_payload_t;

MIGRATE (0x0B) - Dual Jump Tables

typedef struct {
    uint32_t phase;         // 0=prepare, 1=transfer, 2=commit, 3=cleanup
    uint32_t subcmd;        // Sub-command index (0-15 for each table)
    uint64_t src_vf;        // Source VF
    uint64_t dst_vf;        // Destination VF
    uint64_t data_ptr;      // Migration data buffer
    uint64_t data_size;     // Buffer size
    uint32_t flags;         // LIVE, POSTCOPY, etc.
    uint32_t reserved;
} migrate_payload_t;

Wire Format (Host → GSP)

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.

Message Header (64 bytes)

typedef struct {
    uint32_t magic;         // 0x47535052 ("GSPR")
    uint32_t version;       // Protocol version (1)
    uint32_t rpc_type;      // 0x01-0x0C
    uint32_t sequence;      // Monotonic sequence
    uint64_t timestamp_ns;  // Submission timestamp
    uint32_t payload_size;  // Size of payload
    uint32_t flags;         // MSG_SYNC, MSG_ASYNC, MSG_NOREPLY
    uint64_t correlation_id;// For async matching
    uint64_t reserved[3];   // Padding to 64 bytes
} __attribute__((packed)) rpc_header_t;

Complete Message

+------------------+
| rpc_header_t     |  64 bytes
+------------------+
| payload (varies) |  payload_size bytes
+------------------+
| padding to 256B  |  (alignment)
+------------------+

Response Format

Synchronous Response

typedef struct {
    int64_t status;         // 0 = success, negative = error
    uint32_t rpc_type;      // Echo of request
    uint32_t sequence;      // Echo of request
    uint64_t timestamp_ns;  // Completion timestamp
    uint32_t payload_size;  // Response payload size
    uint32_t reserved;
} __attribute__((packed)) rpc_response_header_t;

Error Codes

Code Name Description
0 OK Success
-1 (0xFFFF) EPERM Permission denied
-2 (0xFFFE) ENOENT Not found
-3 (0xFFFD) EINVAL Invalid argument
-6 (0xFFFA) ENODEV No such device
-12 (0xFFF4) ENOMEM Out of memory
-16 (0xFFEE) EBUSY Resource busy
-22 (0xFFEA) EINVAL Invalid argument
-28 (0xFFE4) ENOSPC No space left
-37 (0xFFDB) ENOLCK No locks available
-56 (0xFFC8) EBADMSG Bad message
-84 (0xFFAC) EOVERFLOW Value too large
-90 (0xFFA6) ENOSTR Not a stream
-91 (0xFFA5) ENODATA No data available
-94 (0xFFA2) ENOSR Out of streams resources
-97 (0xFF9F) EPROTO Protocol error
-111 (0xFF91) ETIMEDOUT Connection timed out

Kernel Client Implementation

Message Builder

static int gsp_rpc_send(gsp_client_t *client, uint32_t rpc_type, 
                        void *payload, size_t payload_size,
                        void *response, size_t *response_size) {
    rpc_header_t hdr = {
        .magic = 0x47535052,
        .version = 1,
        .rpc_type = rpc_type,
        .sequence = atomic_inc(&client->seq),
        .timestamp_ns = ktime_get_ns(),
        .payload_size = payload_size,
        .flags = MSG_SYNC,
    };
    
    // Build complete message
    uint8_t msg[256];
    memcpy(msg, &hdr, sizeof(hdr));
    memcpy(msg + 64, payload, payload_size);
    
    // Submit to GSP doorbell
    return gsp_doorbell_ring(client->gsp, msg, sizeof(msg));
}

Doorbell Mechanism

// GSP doorbell register (PCIe BAR0 + offset)
#define GSP_DOORBELL_OFFSET  0x1000

static void gsp_doorbell_ring(gsp_device_t *gsp, void *msg, size_t len) {
    // Copy message to shared memory ring
    // Ring GSP doorbell
    writel(1, gsp->bar0 + GSP_DOORBELL_OFFSET);
}

Async Completion

Notification Mechanism

typedef struct {
    uint32_t rpc_type;
    uint32_t sequence;
    int64_t status;
    uint64_t timestamp_ns;
    uint32_t payload_size;
    uint32_t reserved;
} async_completion_t;

// Delivered via MSI-X or GSP notification queue

Reference

  • Primary Dispatcher: 0x057A1AC0
  • Secondary Dispatcher: 0x04ED39DC
  • Jump Table: 0x057A3AD8 (32 entries)
  • RPC Type Jump Table: 0x059BFEB0 (12 types)