Skip to main content
The Xenia memory subsystem emulates the Xbox 360’s unified memory architecture, providing both virtual and physical memory spaces that are accessible to both CPU and GPU.

Xbox 360 Memory

The Xbox 360 has a unified memory architecture:
  • Total RAM: 512 MB GDDR3 shared between CPU and GPU
  • Memory Type: GDDR3 (Graphics Double Data Rate 3)
  • Bandwidth: 22.4 GB/s to CPU, 256 GB/s to GPU via EDRAM
  • Architecture: Unified Memory Architecture (UMA) - CPU and GPU share same physical RAM
This differs from PCs of the era which had separate system RAM and VRAM.

Memory Subsystem Overview

Xenia’s memory system (src/xenia/memory.h) maps guest memory to host address space:
  • Virtual Memory Base - Usually 0x100000000 (4GB offset)
  • Physical Memory Base - Usually 0x200000000 (8GB offset)
  • Fallback - If base addresses unavailable, shifted left 1 bit until free range found
Guest code only accesses these mapped ranges, not arbitrary host memory.

Memory Map

The Xbox 360 uses a 32-bit address space divided into regions:
From docs/cpu.md memory section.

Virtual Memory Regions

0x00000000 - 0x7FFFFFFF (2 GB) Dynamic virtual memory allocated by games:
  • Applications use NtAllocateVirtualMemory to allocate
  • 4KB or 64KB page sizes
  • Can be reserved, committed, or freed
  • Protected with read/write/execute flags
  • Used for heap allocations, stacks, data structures

XEX Regions

0x80000000 - 0x9FFFFFFF (512 MB) Xbox Executable (XEX) image space:
  • Executable code sections
  • Read-only data sections
  • Encrypted sections (0x8C000000-0x8FFFFFFF)
  • Mix of 4KB and 64KB pages

Physical Memory Regions

0xA0000000 - 0xFFFFFFFF (1536 MB, overlapped) Three overlapping views of physical memory:
  • 0xA0000000-0xBFFFFFFF: 64KB pages
  • 0xC0000000-0xDFFFFFFF: 16MB pages
  • 0xE0000000-0xFFFFFFFF: 4KB pages
All three ranges map to the same physical memory, just with different page alignments. Why overlapping regions? Different page sizes serve different purposes:
  • 64KB pages: Standard allocations, good balance
  • 16MB pages: Large contiguous allocations (framebuffers, textures)
  • 4KB pages: Fine-grained allocations, partial page protection

Virtual to Physical Mapping

Virtual pages can be mapped to physical memory:
When a virtual page at 0xA0000000+ is allocated and mapped to physical memory, it points to the same physical RAM as the corresponding address in the physical memory base.

4KB Physical Page Offset

The range 0xE0000000-0xFFFFFFFF has a special 4KB offset:
  • On Windows, memory mappings must be 64KB-aligned
  • This range needs 4KB granularity
  • A single 4KB offset is added when converting addresses in this range
Games have code that depends on this offset (from docs/cpu.md):
This calculates whether to add the page offset based on the address range.

Heap Management

Memory is managed through heap objects (src/xenia/memory.h:102):

Page Table

Each heap maintains a page table describing allocations:
From src/xenia/memory.h:82. The page table tracks:
  • Which pages are allocated vs free
  • Protection flags (read/write/execute)
  • Whether pages are reserved or committed
  • Size of each allocation region

Allocation Strategy

Heaps support two allocation strategies: Bottom-up (default):
  • Search from low addresses toward high
  • Allocates predictable locations
  • Matches most game expectations
Top-down:
  • Search from high addresses toward low
  • Used by some system allocations
  • Reduces fragmentation for certain patterns

Memory Protection

Pages have protection flags (from src/xenia/memory.h:51):
Protection is enforced by:
  • Host OS page protection (where possible)
  • Manual checks in memory access code
  • MMU handlers for invalid accesses

Allocation Functions

Games allocate memory through kernel functions:

NtAllocateVirtualMemory

Allocates virtual memory:
  • Allocates from 0x00000000-0x7FFFFFFF range
  • Can reserve address space without committing
  • Sets protection flags

MmAllocatePhysicalMemoryEx

Allocates physical memory:
  • Allocates from physical memory (0x00000000+ in physical base)
  • Accessible via 0xA0000000+ virtual addresses
  • GPU can access physical memory directly
  • Used for framebuffers, textures, command buffers

Memory-Mapped I/O (MMIO)

Certain address ranges trigger I/O instead of memory access:
  • GPU registers: Writes to register addresses update GPU state
  • Audio registers: Control audio hardware
  • Hardware registers: Other hardware control
MMIO is handled by MMIOHandler (src/xenia/cpu/mmio_handler.h):
  1. Access to MMIO range triggers page fault
  2. Exception handler intercepts fault
  3. Handler dispatches to appropriate I/O handler
  4. Result returned to CPU
This allows transparent interception of hardware accesses.

Address Translation

Translating guest addresses to host pointers:

Virtual Address Translation

Simple offset since entire 32-bit space is mapped.

Physical Address Translation

Depends on which virtual window is used:
The host address offset handles the 4KB alignment issue.

Shared Memory

CPU and GPU share the same physical memory:
  • CPU writes command buffers to RAM
  • GPU reads commands from same addresses
  • CPU writes vertex/index buffers
  • GPU reads geometry from same addresses
  • GPU writes framebuffers to RAM
  • CPU can read back results
This shared model requires careful synchronization:
  • Memory barriers ensure visibility
  • Cache coherency must be managed
  • Synchronization primitives prevent races

Memory Debugging

Heap Dumping

BaseHeap::DumpMap() logs all allocations:
Useful for:
  • Tracking memory leaks
  • Understanding allocation patterns
  • Debugging memory corruption

Page Fault Logging

Accesses to unmapped memory trigger page faults:
  • Exception handler logs fault address
  • Helps identify bugs in guest code or emulator
  • Stack traces show code leading to fault

Performance Considerations

Memory Mapping Overhead

Mapping the entire 32-bit address space consumes host virtual address space:
  • 64-bit hosts: 4GB per memory base is negligible
  • 32-bit hosts: Not supported (not enough address space)

Page Protection

Changing page protection is expensive:
  • Requires OS syscalls (mprotect, VirtualProtect)
  • Can flush TLBs
  • Games that frequently change protection may slow down

Cache Coherency

Shared CPU/GPU memory requires coherency management:
  • CPU writes may need explicit flushing
  • GPU reads may need invalidation
  • Modern hosts handle this automatically in most cases

References

  • Memory management kernel functions in src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc
  • Memory class implementation in src/xenia/memory.cc
  • Heap implementations in src/xenia/base/memory.h