Skip to content

rcheevos: add PS3 memory map to consoleinfo.c - #545

Open
Alasonga wants to merge 2 commits into
RetroAchievements:developfrom
Alasonga:feature/ps3-memory-map
Open

rcheevos: add PS3 memory map to consoleinfo.c#545
Alasonga wants to merge 2 commits into
RetroAchievements:developfrom
Alasonga:feature/ps3-memory-map

Conversation

@Alasonga

@Alasonga Alasonga commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Adds rc_memory_regions_playstation3 to consoleinfo.c. Depends on #535

Memory regions

RA address range Size Type Description
0x00000000–0x0FFFFFFF 256 MB SYSTEM_RAM Main RAM (preallocated)
0x10000000–0x2FFFFFFF 512 MB SYSTEM_RAM RSX Context + User RAM (64K pages, lazy)
0x30000000–0x3FFFFFFF 256 MB SYSTEM_RAM User RAM (64K pages, lazy)
0x40000000–0x4FFFFFFF 256 MB SYSTEM_RAM User RAM (1M pages, lazy)

RSX context (0x10000000–0x1FFFFFFF) is GPU DMA memory allocated by sys_rsx_context_allocate before any sys_memory_allocate call. It is fused with the first half of the user64K pool into a single region since they are physically contiguous and game state is not expected in RSX context space.

Address mapping

RA addresses are a 1:1 map to RPCS3 virtual addresses. The RPCS3 read_memory callback returns zeroed bytes for lazy regions that have not yet been allocated, preventing rcheevos from permanently disabling achievements that reference unallocated memory at game load time.

References

Tests

All tests pass (make HAVE_HASH=1 in test/).

Add rc_memory_regions_playstation3 with four regions covering the full
PS3 address space as defined in RPCS3 (vm.cpp g_locations):

- Main RAM:           0x00000000-0x0FFFFFFF (256MB, preallocated)
- User RAM (64K):     0x10000000-0x1FFFFFFF (lazy, sys_memory_allocate 64K)
- Unused gap:         0x20000000-0x2FFFFFFF (declared UNUSED to preserve contiguity)
- User RAM (1M):      0x30000000-0x3FFFFFFF (lazy, sys_memory_allocate 1M)

Lazy regions return zeroed bytes via RPCS3 read_memory callback when not
yet allocated, preventing rcheevos from permanently disabling achievements
that reference unallocated memory at game load time.

Reference: https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Memory/vm.cpp
@Alasonga

Alasonga commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Note: AI tools were used to assist in development. All code was reviewed, tested, and verified manually before submission.

@Jamiras Jamiras left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have sufficient understanding to validate the map itself, but the implementation is approved.

Comment thread src/rcheevos/consoleinfo.c Outdated
sys_rsx_context_allocate (called by cellGcmInit) reserves vm::rsx_context
at 0x10000000 (256 MB) before any sys_memory_allocate call. User64K pool
follows at 0x20000000 (512 MB hardcoded in sys_memory.cpp). User1M lands
at 0x40000000. RSX context is fused with user64K[0] into a single 512 MB
region since they are contiguous and game state is not expected in RSX space.

References:
- vm.cpp:1893 (_find_map scan from 0x10000000)
- sys_rsx.cpp:272 (RSX context 256 MB reservation)
- sys_memory.cpp:105 (user64K 512 MB hardcoded pool)

@Jamiras Jamiras left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not confident that the map is correct, but have to assume it is as the author is more fluent with the target architecture.

@Jamiras

Jamiras commented Sep 6, 2026

Copy link
Copy Markdown
Member

The RPCS3 read_memory callback returns zeroed bytes for lazy regions that have not yet been allocated, preventing rcheevos from permanently disabling achievements that reference unallocated memory at game load time.

That's an accurate, though unfortunate observation. RetroAchievements/RAIntegration#1314 excludes blocks from the search results if the read function returns 0 bytes read. But rc_client will also disable achievements if the read returns 0 bytes and it's not part of a pointer chain.

rcheevos/src/rc_client.c

Lines 5884 to 5896 in e871ef5

/* if we know the address is out of range, and it's part of a pointer chain
* (processing_memref is null), don't bother processing it. */
if (address > client->game->max_valid_address && !client->state.processing_memref)
return 0;
if (num_bytes <= sizeof(value)) {
num_read = client->callbacks.read_memory(address, (uint8_t*)&value, num_bytes, client);
if (num_read == num_bytes)
return value;
}
if (num_read < num_bytes)
rc_client_invalidate_processing_memref(client);

Since the memory isn't pre-distributed we can't just switch read functions after the game loads (use one before load to return dummy data saying the addresses are valid and one after load returning no data for unallocated regions).

As a result, the search space will immediately be 1.3GB (256MBx5), which is the problem the above PR was trying to address. I wonder if we should allow peek_memory to return 0xFFFFFFFF to indicate the address is valid but not yet available?

@Jamiras Jamiras added this to the 12.5 milestone Sep 6, 2026
@Alasonga

Alasonga commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

The RPCS3 read_memory callback returns zeroed bytes for lazy regions that have not yet been allocated, preventing rcheevos from permanently disabling achievements that reference unallocated memory at game load time.

That's an accurate, though unfortunate observation. RetroAchievements/RAIntegration#1314 excludes blocks from the search results if the read function returns 0 bytes read. But rc_client will also disable achievements if the read returns 0 bytes and it's not part of a pointer chain.

rcheevos/src/rc_client.c

Lines 5884 to 5896 in e871ef5

/* if we know the address is out of range, and it's part of a pointer chain
* (processing_memref is null), don't bother processing it. */
if (address > client->game->max_valid_address && !client->state.processing_memref)
return 0;
if (num_bytes <= sizeof(value)) {
num_read = client->callbacks.read_memory(address, (uint8_t*)&value, num_bytes, client);
if (num_read == num_bytes)
return value;
}
if (num_read < num_bytes)
rc_client_invalidate_processing_memref(client);

Since the memory isn't pre-distributed we can't just switch read functions after the game loads (use one before load to return dummy data saying the addresses are valid and one after load returning no data for unallocated regions).

As a result, the search space will immediately be 1.3GB (256MBx5), which is the problem the above PR was trying to address. I wonder if we should allow peek_memory to return 0xFFFFFFFF to indicate the address is valid but not yet available?

There are actually two separate read callbacks in the RPCS3 integration: read_memory for rc_client and readBlock for RAIntegration. So the two concerns can be handled independently.

read_memory already returns zeroed bytes with num_bytes for lazy unallocated regions, so rc_client sees a valid read and achievements aren't invalidated. No sentinel needed.

// vm::try_access reads PS3 virtual memory; returns false for uncommitted lazy pages
static u32 read_memory(u32 address, u8* buffer, u32 num_bytes, rc_client_t*)
{
if (vm::try_access(address, buffer, num_bytes, false))
return num_bytes;

    // lazy banks: return zeros so rc_client sees a valid read, not a failure
    if ((address >= s_bank1_base && address < s_bank1_base + s_bank1_size) ||
        (address >= s_bank2_base && address < s_bank2_base + s_bank2_size) ||
        (address >= s_bank3_base && address < s_bank3_base + s_bank3_size))
    {
        memset(buffer, 0, num_bytes);
        return num_bytes;
    }
    return 0;

}

For the search space, the block reader currently zero-fills unconditionally, which bypasses #1314. Fixing it to return 0 for fully unallocated blocks will let #1314 handle that side naturally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants