Difference between revisions of "BAR Emulation Specification"

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="bar-emulation-specification-gsp-570144w"></span>
= BAR Emulation Specification (GSP 570.144W) =
= BAR Emulation Specification (GSP 570.144W) =


<span id="overview"></span>
<blockquote>'''Historical document — superseded.''' The <code>BAR_TRAP</code> RPC (type 0x0A) described here is '''not used''': in emulation mode it returns <code>-ENOTSUPP</code>, and BAR access is synchronous MMIO through the BAR shadow. Guest-visible BAR windows are BAR0 (16 MB register MMIO), BAR1 (256 MB VRAM aperture) and BAR3 (instance window). Canonical documentation: [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 ==


<span id="key-addresses"></span>
The GSP firmware implements BAR (Base Address Register) emulation for virtual GPU (vGPU) through the '''BAR_TRAP''' RPC (type 0x0A). The main handler at '''0x04CB8188''' (40 KB) manages BAR1 aperture, forced access, and memory backing. '''This RPC is not used by the live path''': in emulation mode <code>BAR_TRAP</code> returns <code>-ENOTSUPP</code>; guest BAR access is handled synchronously as MMIO through the BAR shadow (<code>../kernel/bar_emulation.c</code>), not via an RPC.
 
== Key Addresses ==
== Key Addresses ==


Line 47: Line 48:
|}
|}


<span id="handler-state-machine"></span>
== Handler State Machine ==
== Handler State Machine ==


<span id="main-loop-0x04cb8188"></span>
=== Main Loop (0x04CB8188) ===
=== Main Loop (0x04CB8188) ===


The handler runs a continuous event loop processing BAR trap requests:
The handler runs a continuous event loop processing BAR trap requests:


<syntaxhighlight lang="c">while (true) {
<pre>while (true) {
     // Wait for trap event (bitmask in unaff_s5)
     // Wait for trap event (bitmask in unaff_s5)
     event = wait_for_bar_event;
     event = wait_for_bar_event();
      
      
     switch (event & 0x3F) {
     switch (event &amp; 0x3F) {
         case 0x01:  // BAR1 write access
         case 0x01:  // BAR1 write access
             handle_bar1_write;
             handle_bar1_write();
             break;
             break;
         case 0x02:  // BAR1 read access
         case 0x02:  // BAR1 read access
             handle_bar1_read;
             handle_bar1_read();
             break;
             break;
         case 0x08:  // Aperture configuration
         case 0x08:  // Aperture configuration
             handle_aperture_config;
             handle_aperture_config();
             break;
             break;
         case 0x10:  // ForceBarAccess
         case 0x10:  // ForceBarAccess
             handle_force_access;
             handle_force_access();
             break;
             break;
         case 0x20:  // Bar1Rest (restore)
         case 0x20:  // Bar1Rest (restore)
             handle_bar1_restore;
             handle_bar1_restore();
             break;
             break;
         default:
         default:
             return ERROR_UNKNOWN_EVENT;
             return ERROR_UNKNOWN_EVENT;
     }
     }
}</syntaxhighlight>
}</pre>
<span id="event-bitmask"></span>
 
=== Event Bitmask ===
=== Event Bitmask ===


Line 109: Line 108:
|}
|}


<span id="memory-management"></span>
== Memory Management ==
== Memory Management ==


<span id="allocator-arena-0x429b450"></span>
=== Allocator Arena (0x429B450) ===
=== Allocator Arena (0x429B450) ===


<syntaxhighlight lang="c">// Allocate backing store for BAR emulation
<pre>// Allocate backing store for BAR emulation
void *bar_alloc(size_t size) {
void *bar_alloc(size_t size) {
     // Calls UNK_ram_058A1A9C(0x429B450, size)
     // Calls UNK_ram_058A1A9C(0x429B450, size)
Line 124: Line 121:
void bar_free(void *ptr) {
void bar_free(void *ptr) {
     // Calls UNK_ram_05895BF4(0x429B428, ptr)
     // Calls UNK_ram_05895BF4(0x429B428, ptr)
}</syntaxhighlight>
}</pre>
<span id="allocation-sizes"></span>
 
=== Allocation Sizes ===
=== Allocation Sizes ===


Line 132: Line 129:
* '''Force access buffer''': 0x1000 (4 KB)
* '''Force access buffer''': 0x1000 (4 KB)


<span id="cache-coherency"></span>
=== Cache Coherency ===
=== Cache Coherency ===


<syntaxhighlight lang="c">// Flush cache for DMA
<pre>// Flush cache for DMA
void bar_cache_flush(void *addr, size_t size) {
void bar_cache_flush(void *addr, size_t size) {
     UNK_ram_05895BF4(0x429B428, addr);
     UNK_ram_05895BF4(0x429B428, addr);
     UNK_ram_05895BF4(0x429B428, addr + size);
     UNK_ram_05895BF4(0x429B428, addr + size);
}</syntaxhighlight>
}</pre>
<span id="bar1-emulation-logic"></span>
 
== BAR1 Emulation Logic ==
== BAR1 Emulation Logic ==


<span id="write-path-event-0x01"></span>
=== Write Path (Event 0x01) ===
=== Write Path (Event 0x01) ===


<syntaxhighlight lang="c">int handle_bar1_write(bar_trap_t *trap) {
<pre>int handle_bar1_write(bar_trap_t *trap) {
     // 1. Validate offset within aperture
     // 1. Validate offset within aperture
     if (trap->offset >= bar1_aperture_size)
     if (trap-&gt;offset &gt;= bar1_aperture_size)
         return ERROR_OVERFLOW;
         return ERROR_OVERFLOW;
      
      
     // 2. Check ForceBarAccess flag
     // 2. Check ForceBarAccess flag
     if (force_bar_access && !(trap->flags & FORCE_ALLOWED))
     if (force_bar_access &amp;&amp; !(trap-&gt;flags &amp; FORCE_ALLOWED))
         return ERROR_PERMISSION;
         return ERROR_PERMISSION;
      
      
     // 3. Translate to backing store
     // 3. Translate to backing store
     uint8_t *backing = bar1_backing + trap->offset;
     uint8_t *backing = bar1_backing + trap-&gt;offset;
      
      
     // 4. Perform write (1/2/4/8 bytes)
     // 4. Perform write (1/2/4/8 bytes)
     switch (trap->size) {
     switch (trap-&gt;size) {
         case 1: *backing = trap->value; break;
         case 1: *backing = trap-&gt;value; break;
         case 2: *(uint16_t*)backing = trap->value; break;
         case 2: *(uint16_t*)backing = trap-&gt;value; break;
         case 4: *(uint32_t*)backing = trap->value; break;
         case 4: *(uint32_t*)backing = trap-&gt;value; break;
         case 8: *(uint64_t*)backing = trap->value; break;
         case 8: *(uint64_t*)backing = trap-&gt;value; break;
     }
     }
      
      
     // 5. Flush to device if needed
     // 5. Flush to device if needed
     if (device_needs_flush)
     if (device_needs_flush)
         bar_cache_flush(backing, trap->size);
         bar_cache_flush(backing, trap-&gt;size);
      
      
     return OK;
     return OK;
}</syntaxhighlight>
}</pre>
<span id="read-path-event-0x02"></span>
 
=== Read Path (Event 0x02) ===
=== Read Path (Event 0x02) ===


<syntaxhighlight lang="c">int handle_bar1_read(bar_trap_t *trap) {
<pre>int handle_bar1_read(bar_trap_t *trap) {
     if (trap->offset >= bar1_aperture_size)
     if (trap-&gt;offset &gt;= bar1_aperture_size)
         return ERROR_OVERFLOW;
         return ERROR_OVERFLOW;
      
      
     uint8_t *backing = bar1_backing + trap->offset;
     uint8_t *backing = bar1_backing + trap-&gt;offset;
      
      
     switch (trap->size) {
     switch (trap-&gt;size) {
         case 1: *trap->out_value = *backing; break;
         case 1: *trap-&gt;out_value = *backing; break;
         case 2: *trap->out_value = *(uint16_t*)backing; break;
         case 2: *trap-&gt;out_value = *(uint16_t*)backing; break;
         case 4: *trap->out_value = *(uint32_t*)backing; break;
         case 4: *trap-&gt;out_value = *(uint32_t*)backing; break;
         case 8: *trap->out_value = *(uint64_t*)backing; break;
         case 8: *trap-&gt;out_value = *(uint64_t*)backing; break;
     }
     }
      
      
     return OK;
     return OK;
}</syntaxhighlight>
}</pre>
<span id="aperture-configuration-event-0x08"></span>
 
=== Aperture Configuration (Event 0x08) ===
=== Aperture Configuration (Event 0x08) ===


<syntaxhighlight lang="c">int handle_aperture_config(bar_config_t *cfg) {
<pre>int handle_aperture_config(bar_config_t *cfg) {
     // Validate new aperture
     // Validate new aperture
     if (cfg->size > MAX_APERTURE_SIZE)  // 0x40000
     if (cfg-&gt;size &gt; MAX_APERTURE_SIZE)  // 0x40000
         return ERROR_INVALID;
         return ERROR_INVALID;
      
      
     if (cfg->offset & 0xFFF)  // Must be 4KB aligned
     if (cfg-&gt;offset &amp; 0xFFF)  // Must be 4KB aligned
         return ERROR_ALIGNMENT;
         return ERROR_ALIGNMENT;
      
      
     // Reallocate backing store if size changed
     // Reallocate backing store if size changed
     if (cfg->size != bar1_aperture_size) {
     if (cfg-&gt;size != bar1_aperture_size) {
         void *new_backing = bar_alloc(cfg->size);
         void *new_backing = bar_alloc(cfg-&gt;size);
         if (!new_backing) return ERROR_NOMEM;
         if (!new_backing) return ERROR_NOMEM;
          
          
         // Copy existing data
         // Copy existing data
         memcpy(new_backing, bar1_backing,  
         memcpy(new_backing, bar1_backing,  
               min(cfg->size, bar1_aperture_size));
               min(cfg-&gt;size, bar1_aperture_size));
          
          
         bar_free(bar1_backing);
         bar_free(bar1_backing);
         bar1_backing = new_backing;
         bar1_backing = new_backing;
         bar1_aperture_size = cfg->size;
         bar1_aperture_size = cfg-&gt;size;
     }
     }
      
      
     bar1_aperture_offset = cfg->offset;
     bar1_aperture_offset = cfg-&gt;offset;
     return OK;
     return OK;
}</syntaxhighlight>
}</pre>
<span id="forcebaraccess-event-0x10"></span>
 
=== ForceBarAccess (Event 0x10) ===
=== ForceBarAccess (Event 0x10) ===


<syntaxhighlight lang="c">int handle_force_access(force_access_t *fa) {
<pre>int handle_force_access(force_access_t *fa) {
     // ForceBarAccess allows hypervisor to bypass VF permissions
     // ForceBarAccess allows hypervisor to bypass VF permissions
     // Used for live migration, checkpoint/restore
     // Used for live migration, checkpoint/restore
      
      
     force_bar_access = fa->enable;
     force_bar_access = fa-&gt;enable;
     force_access_vf = fa->vf_id;
     force_access_vf = fa-&gt;vf_id;
     force_access_range = fa->range;
     force_access_range = fa-&gt;range;
      
      
     // Allocate shadow buffer for forced operations
     // Allocate shadow buffer for forced operations
     if (fa->enable) {
     if (fa-&gt;enable) {
         force_buffer = bar_alloc(0x1000);
         force_buffer = bar_alloc(0x1000);
         if (!force_buffer) return ERROR_NOMEM;
         if (!force_buffer) return ERROR_NOMEM;
Line 239: Line 234:
      
      
     return OK;
     return OK;
}</syntaxhighlight>
}</pre>
<span id="bar1rest---state-restore-event-0x20"></span>
 
=== Bar1Rest - State Restore (Event 0x20) ===
=== Bar1Rest - State Restore (Event 0x20) ===


<syntaxhighlight lang="c">int handle_bar1_restore(restore_state_t *rs) {
<pre>int handle_bar1_restore(restore_state_t *rs) {
     // Restore BAR1 state from checkpoint
     // Restore BAR1 state from checkpoint
     // Used during VF live migration
     // Used during VF live migration
      
      
     bar1_aperture_offset = rs->aperture_offset;
     bar1_aperture_offset = rs-&gt;aperture_offset;
     bar1_aperture_size = rs->aperture_size;
     bar1_aperture_size = rs-&gt;aperture_size;
     force_bar_access = rs->force_access;
     force_bar_access = rs-&gt;force_access;
      
      
     // Restore backing store from serialized data
     // Restore backing store from serialized data
     if (rs->backing_size > 0) {
     if (rs-&gt;backing_size &gt; 0) {
         void *new_backing = bar_alloc(rs->backing_size);
         void *new_backing = bar_alloc(rs-&gt;backing_size);
         if (!new_backing) return ERROR_NOMEM;
         if (!new_backing) return ERROR_NOMEM;
          
          
         memcpy(new_backing, rs->backing_data, rs->backing_size);
         memcpy(new_backing, rs-&gt;backing_data, rs-&gt;backing_size);
         bar_free(bar1_backing);
         bar_free(bar1_backing);
         bar1_backing = new_backing;
         bar1_backing = new_backing;
Line 262: Line 257:
      
      
     return OK;
     return OK;
}</syntaxhighlight>
}</pre>
<span id="vgpu-io-integration"></span>
 
== vGPU-IO Integration ==
== vGPU-IO Integration ==


<span id="kernel-bar-trap-registration"></span>
=== Kernel BAR Trap Registration ===
=== Kernel BAR Trap Registration ===


<syntaxhighlight lang="c">struct gsp_bar_ops {
<pre>struct gsp_bar_ops {
     int (*bar_trap)(struct gsp_device *gsp,  
     int (*bar_trap)(struct gsp_device *gsp,  
                     struct bar_trap_msg *msg);
                     struct bar_trap_msg *msg);
Line 283: Line 277:
};
};


static const struct gsp_bar_ops gsp_bar_ops = {.bar_trap = gsp_bar_trap_handler,.configure_aperture = gsp_bar_config_aperture,.force_access = gsp_bar_force_access,.save_state = gsp_bar_save_state,.restore_state = gsp_bar_restore_state,
static const struct gsp_bar_ops gsp_bar_ops = {
};</syntaxhighlight>
    .bar_trap = gsp_bar_trap_handler,
<span id="vf-bar-configuration"></span>
    .configure_aperture = gsp_bar_config_aperture,
    .force_access = gsp_bar_force_access,
    .save_state = gsp_bar_save_state,
    .restore_state = gsp_bar_restore_state,
};</pre>
 
=== VF BAR Configuration ===
=== VF BAR Configuration ===


<syntaxhighlight lang="c">int gsp_vf_bar_init(struct gsp_vf *vf) {
<pre>int gsp_vf_bar_init(struct gsp_vf *vf) {
     struct bar_config cfg = {.vf_id = vf->id,.bar = 1,  // BAR1.aperture_offset = vf->bar1_offset,.aperture_size = vf->bar1_size,.flags = BAR_FLAG_COHERENT,
     struct bar_config cfg = {
        .vf_id = vf-&gt;id,
        .bar = 1,  // BAR1
        .aperture_offset = vf-&gt;bar1_offset,
        .aperture_size = vf-&gt;bar1_size,
        .flags = BAR_FLAG_COHERENT,
     };
     };
      
      
     return gsp_rpc_send(vf->gsp, RPC_BAR_TRAP,  
     return gsp_rpc_send(vf-&gt;gsp, RPC_BAR_TRAP,  
                         BAR_SUBCMD_CONFIG, &cfg, sizeof(cfg));
                         BAR_SUBCMD_CONFIG, &amp;cfg, sizeof(cfg));
}</syntaxhighlight>
}</pre>
<span id="live-migration-support"></span>
 
=== Live Migration Support ===
=== Live Migration Support ===


<syntaxhighlight lang="c">// Save BAR state for migration
<pre>// Save BAR state for migration
int gsp_vf_bar_save(struct gsp_vf *vf, void *buf, size_t *size) {
int gsp_vf_bar_save(struct gsp_vf *vf, void *buf, size_t *size) {
     struct bar_save_msg msg = {.vf_id = vf->id,.bar = 1,
     struct bar_save_msg msg = {
        .vf_id = vf-&gt;id,
        .bar = 1,
     };
     };
      
      
     return gsp_rpc_send(vf->gsp, RPC_BAR_TRAP,
     return gsp_rpc_send(vf-&gt;gsp, RPC_BAR_TRAP,
                         BAR_SUBCMD_SAVE, &msg, sizeof(msg),
                         BAR_SUBCMD_SAVE, &amp;msg, sizeof(msg),
                         buf, size);
                         buf, size);
}
}
Line 310: Line 316:
// Restore BAR state on destination
// Restore BAR state on destination
int gsp_vf_bar_restore(struct gsp_vf *vf, void *buf, size_t size) {
int gsp_vf_bar_restore(struct gsp_vf *vf, void *buf, size_t size) {
     struct bar_restore_msg msg = {.vf_id = vf->id,.bar = 1,.data = buf,.data_size = size,
     struct bar_restore_msg msg = {
        .vf_id = vf-&gt;id,
        .bar = 1,
        .data = buf,
        .data_size = size,
     };
     };
      
      
     return gsp_rpc_send(vf->gsp, RPC_BAR_TRAP,
     return gsp_rpc_send(vf-&gt;gsp, RPC_BAR_TRAP,
                         BAR_SUBCMD_RESTORE, &msg, sizeof(msg));
                         BAR_SUBCMD_RESTORE, &amp;msg, sizeof(msg));
}</syntaxhighlight>
}</pre>
<span id="error-handling"></span>
 
== Error Handling ==
== Error Handling ==


Line 346: Line 356:
|}
|}


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


<span id="key-registers-to-monitor"></span>
=== Key Registers to Monitor ===
=== Key Registers to Monitor ===


<pre>0x04296048: Global error flag (cRam0000000004296048)
<pre>0x04296048 : Global error flag (cRam0000000004296048)
0x0429B750: Error status (0x111300 offset)
0x0429B750 : Error status (0x111300 offset)
0x429B428: Cache management base
0x429B428   : Cache management base
0x429B450: Allocator arena base</pre>
0x429B450   : Allocator arena base</pre>
<span id="log-strings"></span>
 
=== Log Strings ===
=== Log Strings ===


Line 367: Line 375:
* <code>Bar1Size</code> - Size queries
* <code>Bar1Size</code> - Size queries


-----
----


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



Revision as of 04:09, 12 October 2026

BAR Emulation Specification (GSP 570.144W)

Historical document — superseded. The BAR_TRAP RPC (type 0x0A) described here is not used: in emulation mode it returns -ENOTSUPP, and BAR access is synchronous MMIO through the BAR shadow. Guest-visible BAR windows are BAR0 (16 MB register MMIO), BAR1 (256 MB VRAM aperture) and BAR3 (instance window). Canonical documentation: ../docs/03-architecture/06-host-module-and-hybrid-model.md.

Overview

The GSP firmware implements BAR (Base Address Register) emulation for virtual GPU (vGPU) through the BAR_TRAP RPC (type 0x0A). The main handler at 0x04CB8188 (40 KB) manages BAR1 aperture, forced access, and memory backing. This RPC is not used by the live path: in emulation mode BAR_TRAP returns -ENOTSUPP; guest BAR access is handled synchronously as MMIO through the BAR shadow (../kernel/bar_emulation.c), not via an RPC.

Key Addresses

Component Address Description
BAR Trap Handler 0x04CB8188 Main emulation logic (40 KB)
RPC Jump Table Entry 0x057675B7 BAR_TRAP in secondary dispatcher
String: BAR1 0x0406570E, 0x04085DE0 BAR1 identifier
String: Bar1Rest 0x040656DA BAR1 restore state
String: ForceBarAccess 0x040656F2 Forced access control
String: Bar1Aperture 0x04065722 Aperture configuration
Memory Allocator 0x429B450 Arena for BAR backing store
Cache Management 0x429B428 Flush/invalidate

Handler State Machine

Main Loop (0x04CB8188)

The handler runs a continuous event loop processing BAR trap requests:

while (true) {
    // Wait for trap event (bitmask in unaff_s5)
    event = wait_for_bar_event();
    
    switch (event & 0x3F) {
        case 0x01:  // BAR1 write access
            handle_bar1_write();
            break;
        case 0x02:  // BAR1 read access
            handle_bar1_read();
            break;
        case 0x08:  // Aperture configuration
            handle_aperture_config();
            break;
        case 0x10:  // ForceBarAccess
            handle_force_access();
            break;
        case 0x20:  // Bar1Rest (restore)
            handle_bar1_restore();
            break;
        default:
            return ERROR_UNKNOWN_EVENT;
    }
}

Event Bitmask

Bit Event Description
0 BAR1_WRITE Guest VF wrote to BAR1
1 BAR1_READ Guest VF read from BAR1
3 APERTURE Aperture size/offset change
4 FORCE_ACCESS ForceBarAccess triggered
5 BAR1_REST Restore BAR1 state

Memory Management

Allocator Arena (0x429B450)

// Allocate backing store for BAR emulation
void *bar_alloc(size_t size) {
    // Calls UNK_ram_058A1A9C(0x429B450, size)
    // Returns pointer in 0x429B000 region
}

// Free backing store
void bar_free(void *ptr) {
    // Calls UNK_ram_05895BF4(0x429B428, ptr)
}

Allocation Sizes

  • Standard BAR1 page: 0x1000 (4 KB)
  • Aperture buffer: 0x40000 (256 KB) max
  • Force access buffer: 0x1000 (4 KB)

Cache Coherency

// Flush cache for DMA
void bar_cache_flush(void *addr, size_t size) {
    UNK_ram_05895BF4(0x429B428, addr);
    UNK_ram_05895BF4(0x429B428, addr + size);
}

BAR1 Emulation Logic

Write Path (Event 0x01)

int handle_bar1_write(bar_trap_t *trap) {
    // 1. Validate offset within aperture
    if (trap->offset >= bar1_aperture_size)
        return ERROR_OVERFLOW;
    
    // 2. Check ForceBarAccess flag
    if (force_bar_access && !(trap->flags & FORCE_ALLOWED))
        return ERROR_PERMISSION;
    
    // 3. Translate to backing store
    uint8_t *backing = bar1_backing + trap->offset;
    
    // 4. Perform write (1/2/4/8 bytes)
    switch (trap->size) {
        case 1: *backing = trap->value; break;
        case 2: *(uint16_t*)backing = trap->value; break;
        case 4: *(uint32_t*)backing = trap->value; break;
        case 8: *(uint64_t*)backing = trap->value; break;
    }
    
    // 5. Flush to device if needed
    if (device_needs_flush)
        bar_cache_flush(backing, trap->size);
    
    return OK;
}

Read Path (Event 0x02)

int handle_bar1_read(bar_trap_t *trap) {
    if (trap->offset >= bar1_aperture_size)
        return ERROR_OVERFLOW;
    
    uint8_t *backing = bar1_backing + trap->offset;
    
    switch (trap->size) {
        case 1: *trap->out_value = *backing; break;
        case 2: *trap->out_value = *(uint16_t*)backing; break;
        case 4: *trap->out_value = *(uint32_t*)backing; break;
        case 8: *trap->out_value = *(uint64_t*)backing; break;
    }
    
    return OK;
}

Aperture Configuration (Event 0x08)

int handle_aperture_config(bar_config_t *cfg) {
    // Validate new aperture
    if (cfg->size > MAX_APERTURE_SIZE)  // 0x40000
        return ERROR_INVALID;
    
    if (cfg->offset & 0xFFF)  // Must be 4KB aligned
        return ERROR_ALIGNMENT;
    
    // Reallocate backing store if size changed
    if (cfg->size != bar1_aperture_size) {
        void *new_backing = bar_alloc(cfg->size);
        if (!new_backing) return ERROR_NOMEM;
        
        // Copy existing data
        memcpy(new_backing, bar1_backing, 
               min(cfg->size, bar1_aperture_size));
        
        bar_free(bar1_backing);
        bar1_backing = new_backing;
        bar1_aperture_size = cfg->size;
    }
    
    bar1_aperture_offset = cfg->offset;
    return OK;
}

ForceBarAccess (Event 0x10)

int handle_force_access(force_access_t *fa) {
    // ForceBarAccess allows hypervisor to bypass VF permissions
    // Used for live migration, checkpoint/restore
    
    force_bar_access = fa->enable;
    force_access_vf = fa->vf_id;
    force_access_range = fa->range;
    
    // Allocate shadow buffer for forced operations
    if (fa->enable) {
        force_buffer = bar_alloc(0x1000);
        if (!force_buffer) return ERROR_NOMEM;
    } else {
        bar_free(force_buffer);
        force_buffer = NULL;
    }
    
    return OK;
}

Bar1Rest - State Restore (Event 0x20)

int handle_bar1_restore(restore_state_t *rs) {
    // Restore BAR1 state from checkpoint
    // Used during VF live migration
    
    bar1_aperture_offset = rs->aperture_offset;
    bar1_aperture_size = rs->aperture_size;
    force_bar_access = rs->force_access;
    
    // Restore backing store from serialized data
    if (rs->backing_size > 0) {
        void *new_backing = bar_alloc(rs->backing_size);
        if (!new_backing) return ERROR_NOMEM;
        
        memcpy(new_backing, rs->backing_data, rs->backing_size);
        bar_free(bar1_backing);
        bar1_backing = new_backing;
    }
    
    return OK;
}

vGPU-IO Integration

Kernel BAR Trap Registration

struct gsp_bar_ops {
    int (*bar_trap)(struct gsp_device *gsp, 
                    struct bar_trap_msg *msg);
    int (*configure_aperture)(struct gsp_device *gsp,
                              uint32_t vf_id,
                              uint64_t offset, uint64_t size);
    int (*force_access)(struct gsp_device *gsp,
                        uint32_t vf_id, bool enable);
    int (*save_state)(struct gsp_device *gsp,
                      uint32_t vf_id, void *buf, size_t *size);
    int (*restore_state)(struct gsp_device *gsp,
                         uint32_t vf_id, void *buf, size_t size);
};

static const struct gsp_bar_ops gsp_bar_ops = {
    .bar_trap = gsp_bar_trap_handler,
    .configure_aperture = gsp_bar_config_aperture,
    .force_access = gsp_bar_force_access,
    .save_state = gsp_bar_save_state,
    .restore_state = gsp_bar_restore_state,
};

VF BAR Configuration

int gsp_vf_bar_init(struct gsp_vf *vf) {
    struct bar_config cfg = {
        .vf_id = vf->id,
        .bar = 1,  // BAR1
        .aperture_offset = vf->bar1_offset,
        .aperture_size = vf->bar1_size,
        .flags = BAR_FLAG_COHERENT,
    };
    
    return gsp_rpc_send(vf->gsp, RPC_BAR_TRAP, 
                        BAR_SUBCMD_CONFIG, &cfg, sizeof(cfg));
}

Live Migration Support

// Save BAR state for migration
int gsp_vf_bar_save(struct gsp_vf *vf, void *buf, size_t *size) {
    struct bar_save_msg msg = {
        .vf_id = vf->id,
        .bar = 1,
    };
    
    return gsp_rpc_send(vf->gsp, RPC_BAR_TRAP,
                        BAR_SUBCMD_SAVE, &msg, sizeof(msg),
                        buf, size);
}

// Restore BAR state on destination
int gsp_vf_bar_restore(struct gsp_vf *vf, void *buf, size_t size) {
    struct bar_restore_msg msg = {
        .vf_id = vf->id,
        .bar = 1,
        .data = buf,
        .data_size = size,
    };
    
    return gsp_rpc_send(vf->gsp, RPC_BAR_TRAP,
                        BAR_SUBCMD_RESTORE, &msg, sizeof(msg));
}

Error Handling

Error Code Recovery
OOM (0x51) Allocator exhausted Shrink aperture, retry
Timeout (0x1E) Cache flush timeout Reset BAR, reinitialize
Invalid (0x1F) Bad aperture config Validate alignment/size
Permission (0xFFFF) ForceAccess violation Check VF permissions
Overflow (0x25) Offset beyond aperture Bounds check in VF driver

Debugging

Key Registers to Monitor

0x04296048  : Global error flag (cRam0000000004296048)
0x0429B750  : Error status (0x111300 offset)
0x429B428   : Cache management base
0x429B450   : Allocator arena base

Log Strings

Search for these in GSP logs:

  • BAR1 - BAR1 access
  • Bar1Rest - State restore
  • ForceBarAccess - Forced access
  • Bar1Aperture - Aperture changes
  • Bar1Size - Size queries

Reference

  • Handler: FUN_ram_04cb8188_ram_04cb8188.c (40 KB)
  • RPC Type: 0x0A (BAR_TRAP)
  • Jump Table Entry: 0x057675B7