summaryrefslogtreecommitdiffstats
path: root/wiki/Migration-Protocol.md
blob: 4fbc879be40f662dbb56d77b745569484d298c67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# Migration Protocol (RPC 0x0B)

## 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)
```c
// 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

```c
// 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

```c
// 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

```c
// 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)
```c
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

```c
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:

```c
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
```c
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
```c
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
```c
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
```c
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
```c
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
```c
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
```c
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/