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 (Re-sync page from tracked wiki source: fix cross-document links and diagram; refresh status)
Line 1: Line 1:
<span id="gsp-rpc-message-format-specification"></span>
= 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/blob/master/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/blob/master/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 10:
* '''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 24:
     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 44:
| FREE
| FREE
| 0-31
| 0-31
|
|  
|-
|-
| 0x03
| 0x03
Line 98: Line 97:
|}
|}


<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 143:
     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 160:
   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 177:
     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 189:
     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 200:
     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 210:
     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 222:
     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 235:
     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 253:
     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 264:
| 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 276:
     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 355:
|}
|}


<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 389:
     // 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 405:
} 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 ==



Revision as of 04:10, 12 October 2026

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)