RPC Message Format
GSP RPC Message Format Specification
Historical document — superseded. This page describes the legacy BAR0 mailbox RPC model: the 64-byte
GSPRmagic 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 (signature0x43505256, header version0x03000000); functions are a flat enum (SET_GUEST_SYSTEM_INFO1,FREE10,GET_GSP_STATIC_INFO65,GSP_RM_CONTROL76,GSP_RM_ALLOC103, ...). Canonical documentation:../docs/03-architecture/03-gsp-and-gsp-rm.mdand../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)