Difference between revisions of "Migration Protocol"

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="migration-protocol-rpc-0x0b"></span>
= Migration Protocol (RPC 0x0B) =
= Migration Protocol (RPC 0x0B) =


<span id="overview"></span>
<blockquote>'''Historical document — superseded.''' This page records the MIGRATE RPC (type 0x0B) as seen in firmware analysis; in emulation mode the MIGRATE RPC returns <code>-ENOTSUPP</code>. The live migration implementation is [https://git.vgpu.io/open-iov/blob/master/kernel/migration.c <code>../kernel/migration.c</code>]; design and status are documented in [https://git.vgpu.io/open-iov/blob/master/docs/04-implementation <code>../docs/04-implementation/</code>].</blockquote>
 
== Overview ==
== Overview ==


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.
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.
<span id="key-addresses"></span>
 
== Key Addresses ==
== Key Addresses ==


<span id="migration-jump-tables"></span>
=== Migration Jump Tables ===
=== Migration Jump Tables ===


<span id="table-1-0x04179ed8-primary-migrate-branch-at-0x057a1bdc"></span>
==== Table 1: 0x04179ED8 (Primary MIGRATE branch at 0x057A1BDC) ====
==== Table 1: 0x04179ED8 (Primary MIGRATE branch at 0x057A1BDC) ====


Line 103: Line 101:
|}
|}


<span id="table-2-0x04179fbc-primary-migrate-branch-at-0x057a1d5c"></span>
==== Table 2: 0x04179FBC (Primary MIGRATE branch at 0x057A1D5C) ====
==== Table 2: 0x04179FBC (Primary MIGRATE branch at 0x057A1D5C) ====


Line 194: Line 191:
|}
|}


<span id="migration-phases"></span>
== Migration Phases ==
== Migration Phases ==


<span id="phase-0-discovery-pre-migration"></span>
=== Phase 0: Discovery (Pre-migration) ===
=== Phase 0: Discovery (Pre-migration) ===


<syntaxhighlight lang="c">// Query VF migratability
<pre>// Query VF migratability
int gsp_migrate_query(struct gsp_vf *vf, struct migrate_query *out) {
int gsp_migrate_query(struct gsp_vf *vf, struct migrate_query *out) {
     migrate_payload_t payload = {.phase = MIGRATE_PHASE_QUERY,.subcmd = 0,.src_vf = vf->id,.dst_vf = 0,
     migrate_payload_t payload = {
        .phase = MIGRATE_PHASE_QUERY,
        .subcmd = 0,
        .src_vf = vf-&gt;id,
        .dst_vf = 0,
     };
     };
     return gsp_rpc_send(vf->gsp, RPC_MIGRATE, &payload, sizeof(payload), out, sizeof(*out));
     return gsp_rpc_send(vf-&gt;gsp, RPC_MIGRATE, &amp;payload, sizeof(payload), out, sizeof(*out));
}</syntaxhighlight>
}</pre>
<span id="phase-1-prepare-table-1-indices-0-11"></span>
 
=== Phase 1: Prepare (Table 1, indices 0-11) ===
=== Phase 1: Prepare (Table 1, indices 0-11) ===


'''Goal''': Quiesce VF, prepare memory state for transfer
'''Goal''': Quiesce VF, prepare memory state for transfer


<syntaxhighlight lang="c">// Subcmd 3 (0x057A22F8) - Returns ID 0x10
<pre>// Subcmd 3 (0x057A22F8) - Returns ID 0x10
int migrate_prepare_quiesce(vf_id) {
int migrate_prepare_quiesce(vf_id) {
     // 1. Pause VF scheduling
     // 1. Pause VF scheduling
Line 226: Line 225:
     // 4. Snapshot page tables
     // 4. Snapshot page tables
     // 5. Return snapshot handle
     // 5. Return snapshot handle
}</syntaxhighlight>
}</pre>
<span id="phase-2-transfer-table-1-index-13-table-2-indices-0-11"></span>
 
=== Phase 2: Transfer (Table 1 index 13, Table 2 indices 0-11) ===
=== Phase 2: Transfer (Table 1 index 13, Table 2 indices 0-11) ===


'''Goal''': Transfer memory pages to destination
'''Goal''': Transfer memory pages to destination


<syntaxhighlight lang="c">// Table 2, subcmd 0 (0x057A257C)
<pre>// Table 2, subcmd 0 (0x057A257C)
int migrate_transfer_pages(vf_id, page_list, *progress) {
int migrate_transfer_pages(vf_id, page_list, *progress) {
     // 1. Iterate page list
     // 1. Iterate page list
Line 245: Line 244:
int migrate_track_dirty(vf_id, *dirty_bitmap) {
int migrate_track_dirty(vf_id, *dirty_bitmap) {
     // Return bitmap of pages dirtied since last transfer
     // Return bitmap of pages dirtied since last transfer
}</syntaxhighlight>
}</pre>
<span id="phase-3-commit-table-2-indices-12-15"></span>
 
=== Phase 3: Commit (Table 2 indices 12-15) ===
=== Phase 3: Commit (Table 2 indices 12-15) ===


'''Goal''': Final synchronization, cutover to destination
'''Goal''': Final synchronization, cutover to destination


<syntaxhighlight lang="c">// Subcmd 12 (0x057A345C)
<pre>// Subcmd 12 (0x057A345C)
int migrate_commit_finalize(vf_id, dst_vf_id) {
int migrate_commit_finalize(vf_id, dst_vf_id) {
     // 1. Final dirty page transfer
     // 1. Final dirty page transfer
Line 266: Line 265:
     // 3. Verify device state
     // 3. Verify device state
     // 4. Return PASS/FAIL
     // 4. Return PASS/FAIL
}</syntaxhighlight>
}</pre>
<span id="phase-4-cleanup-post-migration"></span>
 
=== Phase 4: Cleanup (Post-migration) ===
=== Phase 4: Cleanup (Post-migration) ===


<syntaxhighlight lang="c">int migrate_cleanup(src_vf_id) {
<pre>int migrate_cleanup(src_vf_id) {
     // 1. Release pinned memory
     // 1. Release pinned memory
     // 2. Free snapshot buffers
     // 2. Free snapshot buffers
     // 3. Remove WPR regions
     // 3. Remove WPR regions
     // 4. Destroy migration context
     // 4. Destroy migration context
}</syntaxhighlight>
}</pre>
<span id="migration-message-format"></span>
 
== Migration Message Format ==
== Migration Message Format ==


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint32_t phase;        // MIGRATE_PHASE_*
     uint32_t phase;        // MIGRATE_PHASE_*
     uint32_t subcmd;        // Sub-command index (0-15 per table)
     uint32_t subcmd;        // Sub-command index (0-15 per table)
Line 297: Line 296:
#define MIGRATE_PHASE_CLEANUP  4
#define MIGRATE_PHASE_CLEANUP  4


#define MIGRATE_FLAG_LIVE      (1<<0)    // Live migration
#define MIGRATE_FLAG_LIVE      (1&lt;&lt;0)    // Live migration
#define MIGRATE_FLAG_POSTCOPY  (1<<1)    // Post-copy mode
#define MIGRATE_FLAG_POSTCOPY  (1&lt;&lt;1)    // Post-copy mode
#define MIGRATE_FLAG_AUTO_COMMIT (1<<2)  // Auto-commit after transfer
#define MIGRATE_FLAG_AUTO_COMMIT (1&lt;&lt;2)  // Auto-commit after transfer
#define MIGRATE_FLAG_VERIFY    (1<<3)    // Verify integrity</syntaxhighlight>
#define MIGRATE_FLAG_VERIFY    (1&lt;&lt;3)    // Verify integrity</pre>
<span id="sub-command-descriptors-returned-by-handlers"></span>
 
== Sub-Command Descriptors (Returned by Handlers) ==
== Sub-Command Descriptors (Returned by Handlers) ==


All migration handlers follow the primary dispatcher pattern:
All migration handlers follow the primary dispatcher pattern:


<syntaxhighlight lang="c">typedef struct {
<pre>typedef struct {
     uint32_t subcmd_id;    // Constant: 0x10, 0x14, etc.
     uint32_t subcmd_id;    // Constant: 0x10, 0x14, etc.
     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
} migrate_descriptor_t;</syntaxhighlight>
} migrate_descriptor_t;</pre>
'''Known Subcmd IDs''': | Subcmd | ID | Phase | |--------|-----|-------| | 0x057A22F8 (Table1[3]) | 0x10 | Prepare | | 0x057A2344 (Table1[0]) | 0x14 | Prepare | | Others | TBD | Transfer/Commit |
 
'''Known Subcmd IDs''':
 
{| class="wikitable"
|-
! Subcmd
! ID
! Phase
|-
| 0x057A22F8 (Table1[3])
| 0x10
| Prepare
|-
| 0x057A2344 (Table1[0])
| 0x14
| Prepare
|-
| Others
| TBD
| Transfer/Commit
|}


<span id="vgpu-io-integration"></span>
== vGPU-IO Integration ==
== vGPU-IO Integration ==


<span id="migration-state-machine"></span>
=== Migration State Machine ===
=== Migration State Machine ===


<syntaxhighlight lang="c">typedef enum {
<pre>typedef enum {
     MIG_STATE_IDLE = 0,
     MIG_STATE_IDLE = 0,
     MIG_STATE_QUERY,
     MIG_STATE_QUERY,
Line 339: Line 356:
     struct completion comp;
     struct completion comp;
     struct mutex lock;
     struct mutex lock;
};</syntaxhighlight>
};</pre>
<span id="migration-coordinator"></span>
 
=== Migration Coordinator ===
=== Migration Coordinator ===


<syntaxhighlight lang="c">int gsp_migration_start(struct gsp_vf *vf, uint64_t dst_vf) {
<pre>int gsp_migration_start(struct gsp_vf *vf, uint64_t dst_vf) {
     struct gsp_migration *mig = kzalloc(sizeof(*mig), GFP_KERNEL);
     struct gsp_migration *mig = kzalloc(sizeof(*mig), GFP_KERNEL);
     vf->migration = mig;
     vf-&gt;migration = mig;
     mig->vf = vf;
     mig-&gt;vf = vf;
     mig->dst_vf = dst_vf;
     mig-&gt;dst_vf = dst_vf;
     mig->state = MIG_STATE_QUERY;
     mig-&gt;state = MIG_STATE_QUERY;
      
      
     // Phase 0: Query
     // Phase 0: Query
     struct migrate_query qry;
     struct migrate_query qry;
     gsp_migrate_query(vf, &qry);
     gsp_migrate_query(vf, &amp;qry);
     if (!qry.migratable) return -EINVAL;
     if (!qry.migratable) return -EINVAL;
      
      
     // Phase 1: Prepare
     // Phase 1: Prepare
     mig->state = MIG_STATE_PREPARE;
     mig-&gt;state = MIG_STATE_PREPARE;
     migrate_payload_t prep = {.phase = MIGRATE_PHASE_PREPARE,.subcmd = 3,  // Quiesce.src_vf = vf->id,.dst_vf = dst_vf,
     migrate_payload_t prep = {
        .phase = MIGRATE_PHASE_PREPARE,
        .subcmd = 3,  // Quiesce
        .src_vf = vf-&gt;id,
        .dst_vf = dst_vf,
     };
     };
     migrate_descriptor_t desc;
     migrate_descriptor_t desc;
     gsp_rpc_send(vf->gsp, RPC_MIGRATE, &prep, sizeof(prep), &desc, sizeof(desc));
     gsp_rpc_send(vf-&gt;gsp, RPC_MIGRATE, &amp;prep, sizeof(prep), &amp;desc, sizeof(desc));
     mig->token = desc.subcmd_id;  // Use returned token
     mig-&gt;token = desc.subcmd_id;  // Use returned token
      
      
     // Phase 2: Transfer (iterative)
     // Phase 2: Transfer (iterative)
     mig->state = MIG_STATE_TRANSFER;
     mig-&gt;state = MIG_STATE_TRANSFER;
     while (!gsp_migration_transfer_iter(mig)) {
     while (!gsp_migration_transfer_iter(mig)) {
         msleep(10);  // Throttle
         msleep(10);  // Throttle
Line 371: Line 392:
      
      
     // Phase 3: Commit
     // Phase 3: Commit
     mig->state = MIG_STATE_COMMIT;
     mig-&gt;state = MIG_STATE_COMMIT;
     migrate_payload_t commit = {.phase = MIGRATE_PHASE_COMMIT,.subcmd = 12,.src_vf = vf->id,.dst_vf = dst_vf,.token = mig->token,.flags = MIGRATE_FLAG_VERIFY,
     migrate_payload_t commit = {
        .phase = MIGRATE_PHASE_COMMIT,
        .subcmd = 12,
        .src_vf = vf-&gt;id,
        .dst_vf = dst_vf,
        .token = mig-&gt;token,
        .flags = MIGRATE_FLAG_VERIFY,
     };
     };
     gsp_rpc_send(vf->gsp, RPC_MIGRATE, &commit, sizeof(commit), NULL, 0);
     gsp_rpc_send(vf-&gt;gsp, RPC_MIGRATE, &amp;commit, sizeof(commit), NULL, 0);
      
      
     // Phase 4: Cleanup
     // Phase 4: Cleanup
     mig->state = MIG_STATE_CLEANUP;
     mig-&gt;state = MIG_STATE_CLEANUP;
     gsp_migration_cleanup(mig);
     gsp_migration_cleanup(mig);
      
      
     mig->state = MIG_STATE_COMPLETED;
     mig-&gt;state = MIG_STATE_COMPLETED;
     return 0;
     return 0;
}</syntaxhighlight>
}</pre>
<span id="transfer-iteration"></span>
 
=== Transfer Iteration ===
=== Transfer Iteration ===


<syntaxhighlight lang="c">bool gsp_migration_transfer_iter(struct gsp_migration *mig) {
<pre>bool gsp_migration_transfer_iter(struct gsp_migration *mig) {
     migrate_payload_t xfer = {.phase = MIGRATE_PHASE_TRANSFER,.subcmd = 0,.src_vf = mig->vf->id,.dst_vf = mig->dst_vf,.data_ptr = (uint64_t)mig->progress.page_list,.data_size = mig->progress.page_count * sizeof(uint64_t),.token = mig->token,
     migrate_payload_t xfer = {
        .phase = MIGRATE_PHASE_TRANSFER,
        .subcmd = 0,
        .src_vf = mig-&gt;vf-&gt;id,
        .dst_vf = mig-&gt;dst_vf,
        .data_ptr = (uint64_t)mig-&gt;progress.page_list,
        .data_size = mig-&gt;progress.page_count * sizeof(uint64_t),
        .token = mig-&gt;token,
     };
     };
      
      
     struct migrate_progress prog;
     struct migrate_progress prog;
     int ret = gsp_rpc_send(mig->vf->gsp, RPC_MIGRATE,  
     int ret = gsp_rpc_send(mig-&gt;vf-&gt;gsp, RPC_MIGRATE,  
                           &xfer, sizeof(xfer), &prog, sizeof(prog));
                           &amp;xfer, sizeof(xfer), &amp;prog, sizeof(prog));
      
      
     if (ret) return true;  // Error = done
     if (ret) return true;  // Error = done
      
      
     mig->progress.bytes_transferred += prog.bytes_transferred;
     mig-&gt;progress.bytes_transferred += prog.bytes_transferred;
     mig->progress.pages_transferred += prog.pages_transferred;
     mig-&gt;progress.pages_transferred += prog.pages_transferred;
     mig->progress.dirty_pages = prog.dirty_pages;
     mig-&gt;progress.dirty_pages = prog.dirty_pages;
      
      
     // Check if more dirty pages to transfer
     // Check if more dirty pages to transfer
     if (prog.dirty_pages > 0 && !(mig->flags & MIGRATE_FLAG_POSTCOPY)) {
     if (prog.dirty_pages &gt; 0 &amp;&amp; !(mig-&gt;flags &amp; MIGRATE_FLAG_POSTCOPY)) {
         return false;  // Continue iterating
         return false;  // Continue iterating
     }
     }
      
      
     return true;  // Transfer complete
     return true;  // Transfer complete
}</syntaxhighlight>
}</pre>
<span id="post-copy-mode"></span>
 
=== Post-Copy Mode ===
=== Post-Copy Mode ===


<syntaxhighlight lang="c">int gsp_migration_postcopy(struct gsp_migration *mig) {
<pre>int gsp_migration_postcopy(struct gsp_migration *mig) {
     // Enable post-copy on destination
     // Enable post-copy on destination
     migrate_payload_t pc = {.phase = MIGRATE_PHASE_TRANSFER,.subcmd = 11,  // Dirty tracking.src_vf = mig->vf->id,.dst_vf = mig->dst_vf,.flags = MIGRATE_FLAG_POSTCOPY,.token = mig->token,
     migrate_payload_t pc = {
        .phase = MIGRATE_PHASE_TRANSFER,
        .subcmd = 11,  // Dirty tracking
        .src_vf = mig-&gt;vf-&gt;id,
        .dst_vf = mig-&gt;dst_vf,
        .flags = MIGRATE_FLAG_POSTCOPY,
        .token = mig-&gt;token,
     };
     };
      
      
Line 418: Line 458:
     gsp_page_fault_handler = gsp_migration_page_fault;
     gsp_page_fault_handler = gsp_migration_page_fault;
      
      
     return gsp_rpc_send(mig->vf->gsp, RPC_MIGRATE, &pc, sizeof(pc), NULL, 0);
     return gsp_rpc_send(mig-&gt;vf-&gt;gsp, RPC_MIGRATE, &amp;pc, sizeof(pc), NULL, 0);
}</syntaxhighlight>
}</pre>
<span id="integration-with-barwpr"></span>
 
== Integration with BAR/WPR ==
== Integration with BAR/WPR ==


<span id="bar-state-migration"></span>
=== BAR State Migration ===
=== BAR State Migration ===


<syntaxhighlight lang="c">int gsp_migration_bar_save(struct gsp_migration *mig) {
<pre>int gsp_migration_bar_save(struct gsp_migration *mig) {
     // Save BAR1 aperture, force access state
     // Save BAR1 aperture, force access state
     struct bar_save_msg bar_save = {.vf_id = mig->vf->id,.bar = 1,
     struct bar_save_msg bar_save = {
        .vf_id = mig-&gt;vf-&gt;id,
        .bar = 1,
     };
     };
     return gsp_rpc_send(mig->vf->gsp, RPC_BAR_TRAP,
     return gsp_rpc_send(mig-&gt;vf-&gt;gsp, RPC_BAR_TRAP,
                         BAR_SUBCMD_SAVE, &bar_save, sizeof(bar_save),
                         BAR_SUBCMD_SAVE, &amp;bar_save, sizeof(bar_save),
                         mig->bar_state_buf, &mig->bar_state_size);
                         mig-&gt;bar_state_buf, &amp;mig-&gt;bar_state_size);
}
}


int gsp_migration_bar_restore(struct gsp_migration *mig) {
int gsp_migration_bar_restore(struct gsp_migration *mig) {
     // Restore BAR1 on destination
     // Restore BAR1 on destination
     struct bar_restore_msg bar_restore = {.vf_id = mig->dst_vf,.bar = 1,.data = mig->bar_state_buf,.data_size = mig->bar_state_size,
     struct bar_restore_msg bar_restore = {
        .vf_id = mig-&gt;dst_vf,
        .bar = 1,
        .data = mig-&gt;bar_state_buf,
        .data_size = mig-&gt;bar_state_size,
     };
     };
     return gsp_rpc_send(mig->vf->gsp, RPC_BAR_TRAP,
     return gsp_rpc_send(mig-&gt;vf-&gt;gsp, RPC_BAR_TRAP,
                         BAR_SUBCMD_RESTORE, &bar_restore, sizeof(bar_restore));
                         BAR_SUBCMD_RESTORE, &amp;bar_restore, sizeof(bar_restore));
}</syntaxhighlight>
}</pre>
<span id="wpr-region-migration"></span>
 
=== WPR Region Migration ===
=== WPR Region Migration ===


<syntaxhighlight lang="c">int gsp_migration_wpr_save(struct gsp_migration *mig) {
<pre>int gsp_migration_wpr_save(struct gsp_migration *mig) {
     // Save WPR regions for VF
     // Save WPR regions for VF
     migrate_payload_t wpr = {.phase = MIGRATE_PHASE_PREPARE,.subcmd = 4,  // WPR snapshot.src_vf = mig->vf->id,.dst_vf = mig->dst_vf,.token = mig->token,
     migrate_payload_t wpr = {
        .phase = MIGRATE_PHASE_PREPARE,
        .subcmd = 4,  // WPR snapshot
        .src_vf = mig-&gt;vf-&gt;id,
        .dst_vf = mig-&gt;dst_vf,
        .token = mig-&gt;token,
     };
     };
     return gsp_rpc_send(mig->vf->gsp, RPC_MIGRATE, &wpr, sizeof(wpr), NULL, 0);
     return gsp_rpc_send(mig-&gt;vf-&gt;gsp, RPC_MIGRATE, &amp;wpr, sizeof(wpr), NULL, 0);
}</syntaxhighlight>
}</pre>
<span id="error-handling"></span>
 
== Error Handling ==
== Error Handling ==


Line 485: Line 535:
|}
|}


<span id="debugging"></span>
== Debugging ==
== Debugging ==


<span id="migration-trace-points"></span>
=== Migration Trace Points ===
=== Migration Trace Points ===


<syntaxhighlight lang="c">trace_gsp_mig_phase(vf_id, phase, subcmd, token);
<pre>trace_gsp_mig_phase(vf_id, phase, subcmd, token);
trace_gsp_mig_transfer(vf_id, pages, bytes, dirty);
trace_gsp_mig_transfer(vf_id, pages, bytes, dirty);
trace_gsp_mig_commit(vf_id, status, verify);
trace_gsp_mig_commit(vf_id, status, verify);
trace_gsp_mig_error(vf_id, phase, error);</syntaxhighlight>
trace_gsp_mig_error(vf_id, phase, error);</pre>
<span id="gsp-log-strings"></span>
 
=== GSP Log Strings ===
=== GSP Log Strings ===


Line 504: Line 552:
* Commit verification results
* Commit verification results


-----
----


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



Revision as of 04:10, 12 October 2026

Migration Protocol (RPC 0x0B)

Historical document — superseded. This page records the MIGRATE RPC (type 0x0B) as seen in firmware analysis; in emulation mode the MIGRATE RPC returns -ENOTSUPP. The live migration implementation is ../kernel/migration.c; design and status are documented in ../docs/04-implementation/.

Overview

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.

Key Addresses

Migration Jump Tables

Table 1: 0x04179ED8 (Primary MIGRATE branch at 0x057A1BDC)

Index Target Decompiled Description
0 0x057A2344 ✅ Phase 1: Prepare - returns ID 0x14, checks flag at +0x7F9
1 0x057A2320 ✅ Phase 1: Prepare variant
2 0x057A230C ✅ Phase 1: Prepare variant
3 0x057A22F8 ✅ Phase 1: Prepare - returns ID 0x10
4 0x057A2388 ✅ Phase 1: Prepare variant
5 0x057A23D8 ✅ Phase 1: Prepare variant
6 0x057A23AC ✅ Phase 1: Prepare variant
7 0x057A2478 ✅ Phase 1: Prepare variant
8 0x057A2428 ✅ Phase 1: Prepare variant
9 0x057A2454 ✅ Phase 1: Prepare variant
10 0x057A2404 ✅ Phase 1: Prepare variant
11 0x057A2364 ✅ Phase 1: Prepare variant
12 0x057A1F3C (dup) Duplicate entry
13 0x057A299C — Phase 2: Transfer
14 0x057A1F3C (dup) Duplicate entry
15 0x057A1F3C (dup) Duplicate entry

Table 2: 0x04179FBC (Primary MIGRATE branch at 0x057A1D5C)

Index Target Decompiled Description
0 0x057A257C ✅ Phase 2: Transfer
1 0x057A25E4 ✅ Phase 2: Transfer
2 0x057A24EC ✅ Phase 2: Transfer
3 0x057A2608 ✅ Phase 2: Transfer
4 0x057A2534 ✅ Phase 2: Transfer
5 0x057A25C0 ✅ Phase 2: Transfer
6 0x057A24A4 ✅ Phase 2: Transfer
7 0x057A259C ✅ Phase 2: Transfer
8 0x057A2510 ✅ Phase 2: Transfer
9 0x057A2558 ✅ Phase 2: Transfer
10 0x057A24C8 ✅ Phase 2: Transfer
11 0x057A262C ✅ Phase 2: Transfer
12 0x057A345C ✅ Phase 3: Commit
13 0x057A36D8 ✅ Phase 3: Commit
14 0x057A35D8 ✅ Phase 3: Commit
15 0x057A3658 ✅ Phase 3: Commit

Migration Phases

Phase 0: Discovery (Pre-migration)

// Query VF migratability
int gsp_migrate_query(struct gsp_vf *vf, struct migrate_query *out) {
    migrate_payload_t payload = {
        .phase = MIGRATE_PHASE_QUERY,
        .subcmd = 0,
        .src_vf = vf->id,
        .dst_vf = 0,
    };
    return gsp_rpc_send(vf->gsp, RPC_MIGRATE, &payload, sizeof(payload), out, sizeof(*out));
}

Phase 1: Prepare (Table 1, indices 0-11)

Goal: Quiesce VF, prepare memory state for transfer

// Subcmd 3 (0x057A22F8) - Returns ID 0x10
int migrate_prepare_quiesce(vf_id) {
    // 1. Pause VF scheduling
    // 2. Flush pending commands
    // 3. Pin all VF memory
    // 4. Return quiesce token
}

// Subcmd 0 (0x057A2344) - Returns ID 0x14, checks flag at in_t1+0x7F9
int migrate_prepare_snapshot(vf_id, *token) {
    // 1. Snapshot VF register state
    // 2. Snapshot BAR configurations
    // 3. Snapshot WPR regions
    // 4. Snapshot page tables
    // 5. Return snapshot handle
}

Phase 2: Transfer (Table 1 index 13, Table 2 indices 0-11)

Goal: Transfer memory pages to destination

// Table 2, subcmd 0 (0x057A257C)
int migrate_transfer_pages(vf_id, page_list, *progress) {
    // 1. Iterate page list
    // 2. For each page:
    //    a. Copy via DMA (0x0588F9C4)
    //    b. Verify checksum
    //    c. Mark page dirty if modified
    // 3. Return bytes transferred
}

// Table 2, subcmd 11 (0x057A262C) - Dirty page tracking
int migrate_track_dirty(vf_id, *dirty_bitmap) {
    // Return bitmap of pages dirtied since last transfer
}

Phase 3: Commit (Table 2 indices 12-15)

Goal: Final synchronization, cutover to destination

// Subcmd 12 (0x057A345C)
int migrate_commit_finalize(vf_id, dst_vf_id) {
    // 1. Final dirty page transfer
    // 2. Transfer register state
    // 3. Activate destination VF
    // 4. Release source VF resources
    // 5. Notify completion
}

// Subcmd 13 (0x057A36D8)
int migrate_commit_verify(vf_id, *verify_result) {
    // 1. Verify memory integrity
    // 2. Verify register state
    // 3. Verify device state
    // 4. Return PASS/FAIL
}

Phase 4: Cleanup (Post-migration)

int migrate_cleanup(src_vf_id) {
    // 1. Release pinned memory
    // 2. Free snapshot buffers
    // 3. Remove WPR regions
    // 4. Destroy migration context
}

Migration Message Format

typedef struct {
    uint32_t phase;         // MIGRATE_PHASE_*
    uint32_t subcmd;        // Sub-command index (0-15 per table)
    uint64_t src_vf;        // Source VF ID
    uint64_t dst_vf;        // Destination VF ID
    uint64_t data_ptr;      // Data buffer (page list, bitmap, etc.)
    uint64_t data_size;     // Buffer size
    uint32_t flags;         // MIGRATE_LIVE, MIGRATE_POSTCOPY, etc.
    uint32_t reserved;
    uint64_t token;         // Opaque migration token
} __attribute__((packed)) migrate_payload_t;

#define MIGRATE_PHASE_QUERY     0
#define MIGRATE_PHASE_PREPARE   1
#define MIGRATE_PHASE_TRANSFER  2
#define MIGRATE_PHASE_COMMIT    3
#define MIGRATE_PHASE_CLEANUP   4

#define MIGRATE_FLAG_LIVE       (1<<0)    // Live migration
#define MIGRATE_FLAG_POSTCOPY   (1<<1)    // Post-copy mode
#define MIGRATE_FLAG_AUTO_COMMIT (1<<2)  // Auto-commit after transfer
#define MIGRATE_FLAG_VERIFY     (1<<3)    // Verify integrity

Sub-Command Descriptors (Returned by Handlers)

All migration handlers follow the primary dispatcher pattern:

typedef struct {
    uint32_t subcmd_id;     // Constant: 0x10, 0x14, etc.
    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
} migrate_descriptor_t;

Known Subcmd IDs:

Subcmd ID Phase
0x057A22F8 (Table1[3]) 0x10 Prepare
0x057A2344 (Table1[0]) 0x14 Prepare
Others TBD Transfer/Commit

vGPU-IO Integration

Migration State Machine

typedef enum {
    MIG_STATE_IDLE = 0,
    MIG_STATE_QUERY,
    MIG_STATE_PREPARE,
    MIG_STATE_TRANSFER,
    MIG_STATE_COMMIT,
    MIG_STATE_CLEANUP,
    MIG_STATE_FAILED,
    MIG_STATE_COMPLETED
} mig_state_t;

struct gsp_migration {
    struct gsp_vf *vf;
    mig_state_t state;
    uint64_t token;
    uint64_t dst_vf;
    struct migrate_progress progress;
    struct completion comp;
    struct mutex lock;
};

Migration Coordinator

int gsp_migration_start(struct gsp_vf *vf, uint64_t dst_vf) {
    struct gsp_migration *mig = kzalloc(sizeof(*mig), GFP_KERNEL);
    vf->migration = mig;
    mig->vf = vf;
    mig->dst_vf = dst_vf;
    mig->state = MIG_STATE_QUERY;
    
    // Phase 0: Query
    struct migrate_query qry;
    gsp_migrate_query(vf, &qry);
    if (!qry.migratable) return -EINVAL;
    
    // Phase 1: Prepare
    mig->state = MIG_STATE_PREPARE;
    migrate_payload_t prep = {
        .phase = MIGRATE_PHASE_PREPARE,
        .subcmd = 3,  // Quiesce
        .src_vf = vf->id,
        .dst_vf = dst_vf,
    };
    migrate_descriptor_t desc;
    gsp_rpc_send(vf->gsp, RPC_MIGRATE, &prep, sizeof(prep), &desc, sizeof(desc));
    mig->token = desc.subcmd_id;  // Use returned token
    
    // Phase 2: Transfer (iterative)
    mig->state = MIG_STATE_TRANSFER;
    while (!gsp_migration_transfer_iter(mig)) {
        msleep(10);  // Throttle
        if (signal_pending(current)) break;
    }
    
    // Phase 3: Commit
    mig->state = MIG_STATE_COMMIT;
    migrate_payload_t commit = {
        .phase = MIGRATE_PHASE_COMMIT,
        .subcmd = 12,
        .src_vf = vf->id,
        .dst_vf = dst_vf,
        .token = mig->token,
        .flags = MIGRATE_FLAG_VERIFY,
    };
    gsp_rpc_send(vf->gsp, RPC_MIGRATE, &commit, sizeof(commit), NULL, 0);
    
    // Phase 4: Cleanup
    mig->state = MIG_STATE_CLEANUP;
    gsp_migration_cleanup(mig);
    
    mig->state = MIG_STATE_COMPLETED;
    return 0;
}

Transfer Iteration

bool gsp_migration_transfer_iter(struct gsp_migration *mig) {
    migrate_payload_t xfer = {
        .phase = MIGRATE_PHASE_TRANSFER,
        .subcmd = 0,
        .src_vf = mig->vf->id,
        .dst_vf = mig->dst_vf,
        .data_ptr = (uint64_t)mig->progress.page_list,
        .data_size = mig->progress.page_count * sizeof(uint64_t),
        .token = mig->token,
    };
    
    struct migrate_progress prog;
    int ret = gsp_rpc_send(mig->vf->gsp, RPC_MIGRATE, 
                           &xfer, sizeof(xfer), &prog, sizeof(prog));
    
    if (ret) return true;  // Error = done
    
    mig->progress.bytes_transferred += prog.bytes_transferred;
    mig->progress.pages_transferred += prog.pages_transferred;
    mig->progress.dirty_pages = prog.dirty_pages;
    
    // Check if more dirty pages to transfer
    if (prog.dirty_pages > 0 && !(mig->flags & MIGRATE_FLAG_POSTCOPY)) {
        return false;  // Continue iterating
    }
    
    return true;  // Transfer complete
}

Post-Copy Mode

int gsp_migration_postcopy(struct gsp_migration *mig) {
    // Enable post-copy on destination
    migrate_payload_t pc = {
        .phase = MIGRATE_PHASE_TRANSFER,
        .subcmd = 11,  // Dirty tracking
        .src_vf = mig->vf->id,
        .dst_vf = mig->dst_vf,
        .flags = MIGRATE_FLAG_POSTCOPY,
        .token = mig->token,
    };
    
    // Page fault handler on destination
    gsp_page_fault_handler = gsp_migration_page_fault;
    
    return gsp_rpc_send(mig->vf->gsp, RPC_MIGRATE, &pc, sizeof(pc), NULL, 0);
}

Integration with BAR/WPR

BAR State Migration

int gsp_migration_bar_save(struct gsp_migration *mig) {
    // Save BAR1 aperture, force access state
    struct bar_save_msg bar_save = {
        .vf_id = mig->vf->id,
        .bar = 1,
    };
    return gsp_rpc_send(mig->vf->gsp, RPC_BAR_TRAP,
                        BAR_SUBCMD_SAVE, &bar_save, sizeof(bar_save),
                        mig->bar_state_buf, &mig->bar_state_size);
}

int gsp_migration_bar_restore(struct gsp_migration *mig) {
    // Restore BAR1 on destination
    struct bar_restore_msg bar_restore = {
        .vf_id = mig->dst_vf,
        .bar = 1,
        .data = mig->bar_state_buf,
        .data_size = mig->bar_state_size,
    };
    return gsp_rpc_send(mig->vf->gsp, RPC_BAR_TRAP,
                        BAR_SUBCMD_RESTORE, &bar_restore, sizeof(bar_restore));
}

WPR Region Migration

int gsp_migration_wpr_save(struct gsp_migration *mig) {
    // Save WPR regions for VF
    migrate_payload_t wpr = {
        .phase = MIGRATE_PHASE_PREPARE,
        .subcmd = 4,  // WPR snapshot
        .src_vf = mig->vf->id,
        .dst_vf = mig->dst_vf,
        .token = mig->token,
    };
    return gsp_rpc_send(mig->vf->gsp, RPC_MIGRATE, &wpr, sizeof(wpr), NULL, 0);
}

Error Handling

Phase Error Recovery
Prepare EBUSY Wait, retry
Prepare ENOMEM Reduce snapshot size
Transfer ETIMEDOUT Checkpoint, retry
Transfer EIO Failover to post-copy
Commit EINVAL Rollback to source
Commit ENOSPC Expand destination

Debugging

Migration Trace Points

trace_gsp_mig_phase(vf_id, phase, subcmd, token);
trace_gsp_mig_transfer(vf_id, pages, bytes, dirty);
trace_gsp_mig_commit(vf_id, status, verify);
trace_gsp_mig_error(vf_id, phase, error);

GSP Log Strings

Search for migration-related strings in firmware:

  • Migration phase markers
  • Page transfer progress
  • Commit verification results

Reference

  • Primary Dispatcher MIGRATE branches: 0x057A1BDC, 0x057A1D54
  • Jump Table 1: 0x04179ED8 (16 entries)
  • Jump Table 2: 0x04179FBC (16 entries)
  • Decompiled handlers: 28 functions in decompiled/