Files
Sylpheed/docs/reference/xbox360-re-technical-reference.md
sim 6dcdea1cf1 docs(reference): adopt the last reference files from the project root
Three untracked files in the project root had no home in either repository:

- the Xbox 360 technical reference report (a research compilation) becomes
  docs/reference/xbox360-re-technical-reference.md, unchanged;
- XBOX360_ARCHITECTURE.md becomes docs/reference/xbox360-architecture.md,
  trimmed to its platform facts. Its format "status" sections (PAK unknown,
  mesh unknown, audio TODO) and the `just sniff` workflow predate every
  decoder in this repo and were wrong;
- generate_export_docs.py becomes tools/generate_export_docs.py, the path the
  committed xbox360-exports.* already name as their generator. It lived
  inside a Canary checkout, so it now takes --canary and --out and fails
  loudly on a tree that is not Canary.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:19:54 +02:00

839 lines
41 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- Adopted 2026-09-16 from an untracked file in the project root
(compass_artifact_wf-0d76d426-…_text_markdown.md). A research compilation,
not measured by this project: verify a figure before relying on it. -->
# Reverse Engineering Xbox 360: A Complete Technical Reference
**The Xbox 360's architecture — a custom PowerPC CPU, unified-shader GPU, and proprietary OS stack — presents one of the most complex reverse engineering targets in console history.** This document provides a definitive binary-level reference for every major subsystem relevant to game porting, from raw instruction encodings and GPU command packets to file format structs and kernel internals. Every offset, opcode, and constant documented here derives from the Xenia emulator source code, Free60 project research, community reverse engineering, and leaked SDK analysis. All multi-byte fields in Xbox 360 structures are **big-endian** unless explicitly noted otherwise.
---
## 1. IBM Xenon CPU: three in-order PowerPC cores at 3.2 GHz
The Xenon (codenamed "Waternoose") is a custom IBM chip implementing the **PowerPC 2.02 ISA** in 64-bit mode, though games run predominantly in 32-bit addressing. Three symmetric cores share a single die, each running **2 hardware threads (SMT)** for 6 total logical processors. All cores execute **in-order** with dual-issue superscalar pipelines — no out-of-order speculation. The chip clocks at **3.2 GHz** and connects to the Xenos GPU via a **21.6 GB/s front-side bus** (10.8 GB/s per direction).
### Cache hierarchy
| Level | Size | Associativity | Line Size | Notes |
|-------|------|---------------|-----------|-------|
| L1 I-Cache | 32 KB / core | 2-way | 128 bytes | Private per core |
| L1 D-Cache | 32 KB / core | 4-way | 128 bytes | **Write-through, no write-allocate** — writes bypass L1, go to L2 |
| L2 Cache | 1 MB unified | 8-way | 128 bytes | Shared across all 3 cores, 1.6 GHz, 256-bit bus (51.2 GB/s) |
The L1 D-cache's no-write-allocate policy means streaming writes pass directly to L2, preventing cache thrashing for write-heavy workloads. A custom **xDCBT** prefetch instruction bypasses L2 entirely, pulling data into L1 directly. The GPU can **lock L2 lines** for Xbox Procedural Synthesis (XPS), where the CPU generates geometry into locked cache sets that the GPU reads without a main-memory round-trip.
### Register file
Each hardware thread maintains its own independent context — critical for understanding disassembly:
| Register Set | Count × Width | SPR Number | Purpose |
|-------------|---------------|------------|---------|
| GPR r0r31 | 32 × 64-bit | — | General purpose |
| FPR f0f31 | 32 × 64-bit | — | IEEE 754 double-precision floating point |
| VR v0v127 | **128 × 128-bit** | — | VMX-128 vector registers (extended from standard 32) |
| CR | 1 × 32-bit (8 × 4-bit fields) | — | Condition register (CR0CR7) |
| LR | 1 × 64-bit | SPR 8 | Link register (return address) |
| CTR | 1 × 64-bit | SPR 9 | Count register / branch target |
| XER | 1 × 64-bit | SPR 1 | Fixed-point exception (carry, overflow) |
| FPSCR | 1 × 32-bit | — | FP status and control |
| TBL / TBU | 1 × 32-bit each | SPR 268/269 | Time base lower/upper |
| PURR | 1 × 64-bit | SPR 309 | Per-thread cycle counter |
The **VMX-128 extension** is the most significant Xenon-specific ISA change. Standard AltiVec provides 32 vector registers (v0v31) with 5-bit encoding; Xenon extends this to **128 registers per thread** using 7-bit encoding, for **256 × 128-bit registers per core**. Xenon adds single-cycle `vdot3`/`vdot4` dot-product instructions and D3D compressed-format handling instructions absent from standard AltiVec.
### Key instruction encodings
**Atomic operations (load-linked / store-conditional):**
```
lwarx RT, RA, RB — Load Word And Reserve Indexed
Encoding: 0x7C000028 | (RT<<21) | (RA<<16) | (RB<<11)
[31:26]=0b011111 [25:21]=RT [20:16]=RA [15:11]=RB [10:1]=0000010100 [0]=0
stwcx. RS, RA, RB — Store Word Conditional Indexed (always records to CR0)
Encoding: 0x7C00012D | (RS<<21) | (RA<<16) | (RB<<11)
[31:26]=0b011111 [25:21]=RS [20:16]=RA [15:11]=RB [10:1]=0010010110 [0]=1
```
**VMX load/store (128-bit aligned):**
```
lvx VRT, RA, RB — Load Vector Indexed
Primary=31, XO=103. Encoding: 0x7C0000CE | (VRT<<21) | (RA<<16) | (RB<<11)
stvx VRS, RA, RB — Store Vector Indexed
Primary=31, XO=231. Encoding: 0x7C0001CE | (VRS<<21) | (RA<<16) | (RB<<11)
```
**Floating-point special:**
```
fsel FRT, FRA, FRC, FRB — Floating Select (FRT = FRA >= 0 ? FRC : FRB)
Primary=63, XO=23. Encoding: 0xFC00002E | (FRT<<21) | (FRA<<16) | (FRB<<11) | (FRC<<6)
frsqrte FRT, FRB — Floating Reciprocal Square Root Estimate
Primary=63, XO=26. Encoding: 0xFC000034 | (FRT<<21) | (FRB<<11)
```
**Synchronization barriers:**
```
hwsync (sync L=0): 0x7C0004AC — Full memory barrier, drains write buffers
lwsync (sync L=1): 0x7C2004AC — Lightweight barrier, orders loads/stores
eieio: 0x7C0006AC — Enforces I/O ordering for MMIO
```
### Thread scheduling and hardware priority
Games pin work to specific hardware threads (05) via `XSetThreadProcessor()`. Thread 0 on Core 0 is the master thread. The hypervisor controls thread dispatch; hardware thread priority is managed through HID (Hypervisor Implementation-Dependent) registers.
### Physical address space memory map
| Address Range | Size | Description |
|--------------|------|-------------|
| `0x00000000``0x1FFFFFFF` | 512 MB | Main GDDR3 DRAM (unified CPU/GPU) |
| `0x7FEA0000` | ~64 KB | **XMA audio decoder** MMIO registers |
| `0xC0000000``0xC00FFFFF` | ~1 MB | PCI / Southbridge configuration |
| `0xC8000000` | Region | NAND flash controller |
| `0xE0000000``0xEFFFFFFF` | Region | GPU interface / bus region |
| `0xEC800000` | Large region | **Xenos GPU register file** (MMIO) |
Internally, the CPU SoC contains a **32 KB boot ROM**, **64 KB secure SRAM**, **768 eFuse bits** for per-console keys, and a hardware security engine — all accessible only at HV privilege.
---
## 2. Xenos GPU: unified shaders, 10 MB eDRAM, and PM4 command packets
The Xenos is a custom ATI design based on the R400/R500 family — the **world's first GPU with unified shader architecture**, predating even ATI's own R600. It clocks at **500 MHz** with **48 unified shader processors** in 3 SIMD arrays of 16, each with a **5-wide VLIW ALU** (240 ALUs total, **240 GFLOPS peak**). It also serves as the system northbridge, hosting both **64-bit dual memory controllers** (22.4 GB/s to 512 MB GDDR3) and the CPU FSB interface.
### eDRAM: the 10 MB render target cache
A separate daughter die containing **10 MB of embedded DRAM** sits in the GPU package, connected at **32 GB/s** externally but **256 GB/s** between its internal logic and memory cells. This 8:1 bandwidth ratio makes alpha blending, Z/stencil testing, and **4× MSAA essentially free** — all handled by dedicated logic on the eDRAM die without touching the main bus.
**Tile geometry from Xenia (`xenos.h`):**
```
kEdramTileWidthSamples = 80
kEdramTileHeightSamples = 16
kEdramTileCount = 2048
Total = 2048 tiles × 80 × 16 × 4 bytes/sample = 10,485,760 bytes (10 MB)
```
Each tile covers **80 × 16 samples** at 4 bytes per sample = 5,120 bytes. A full 720p (1280×720) frame with 32-bit color + 32-bit depth requires ~7.2 MB, fitting comfortably in eDRAM without tiling. With 4× MSAA at 720p, games must use **predicated tiling** — the GPU replays the command buffer per tile, with hardware predication culling off-tile primitives. The `PM4_SET_BIN_MASK` (0x50) and `PM4_SET_BIN_BASE_OFFSET` (0x4B) commands configure this.
### PM4 command buffer protocol
The GPU consumes commands from a ring buffer in system memory using the **PM4 (Packet Manager 4)** format inherited from ATI R-series GPUs. Three packet types exist:
**Type-0 (Register Write):**
```
Bits [31:30] = 0b00
Bit [29] = ONE_REG_WR (0=sequential, 1=repeated)
Bits [28:16] = COUNT - 1
Bits [15:0] = BASE_INDEX (register DWORD index)
Payload: COUNT DWORDs written to sequential registers starting at BASE_INDEX.
```
**Type-2 (NOP):**
```
Bits [31:30] = 0b10
Bits [29:0] = don't care (padding/alignment filler)
Constant: 0x80000000
```
**Type-3 (IT Command):**
```
Bits [31:30] = 0b11
Bit [29] = PREDICATE (conditional on VIZ query)
Bits [28:16] = COUNT - 1
Bits [15:8] = IT_OPCODE (8-bit)
Bits [7:0] = Reserved
Payload: COUNT DWORDs of command-specific data.
```
### PM4 opcode table (from Xenia `xenos.h`)
| Opcode | Hex | Command |
|--------|-----|---------|
| PM4_NOP | 0x10 | No operation |
| PM4_REG_RMW | 0x21 | Register read-modify-write |
| PM4_DRAW_INDX | 0x22 | Draw indexed primitives |
| PM4_IM_LOAD | 0x27 | Load shader microcode from memory address |
| PM4_IM_LOAD_IMMEDIATE | 0x2B | Load shader microcode inline in packet |
| PM4_IM_STORE | 0x2C | Store shader microcode to system memory |
| PM4_SET_CONSTANT | 0x2D | Set GPU constant registers |
| PM4_LOAD_CONSTANT_CONTEXT | 0x2E | Load constants from memory |
| PM4_DRAW_INDX_2 | 0x36 | Draw with inline index buffer |
| PM4_INDIRECT_BUFFER_PFD | 0x37 | Indirect buffer, pipelined |
| PM4_INVALIDATE_STATE | 0x3B | Selective state invalidation |
| PM4_WAIT_REG_MEM | 0x3C | Wait until register/memory matches value |
| PM4_MEM_WRITE | 0x3D | Write value to memory |
| PM4_REG_TO_MEM | 0x3E | Copy register to memory |
| PM4_INDIRECT_BUFFER | 0x3F | Indirect buffer dispatch |
| PM4_COND_WRITE | 0x45 | Conditional write |
| PM4_EVENT_WRITE | 0x46 | Generate event + memory write on completion |
| PM4_ME_INIT | 0x48 | Microengine initialization |
| PM4_SET_BIN_BASE_OFFSET | 0x4B | Tiled rendering bin offset |
| PM4_SET_BIN_MASK | 0x50 | 64-bit bin mask for tiling |
| PM4_SET_BIN_SELECT | 0x51 | 64-bit bin select |
| PM4_WAIT_REG_EQ | 0x52 | Wait until register == value |
| PM4_WAIT_REG_GTE | 0x53 | Wait until register ≥ value |
| PM4_INTERRUPT | 0x54 | Generate interrupt from command stream |
| PM4_SET_CONSTANT2 | 0x55 | Set constants block 2 |
| PM4_EVENT_WRITE_SHD | 0x58 | VS/PS done event |
| PM4_EVENT_WRITE_CFL | 0x59 | Cache flush done event |
| PM4_EVENT_WRITE_EXT | 0x5A | Screen extent event |
| PM4_EVENT_WRITE_ZPD | 0x5B | Z-pass done event |
| PM4_CONTEXT_UPDATE | 0x5E | Update current context |
| PM4_XE_SWAP | 0x64 | Frame swap (Xenia-specific trigger) |
### GPU register file layout
The Xenos register file is MMIO-mapped at physical **0xEC800000**. Registers are addressed by DWORD index (multiply by 4 for byte offset). Shader constant loading dispatches by type:
| Type Code | Register Base | Contents |
|-----------|--------------|----------|
| 0 | 0x4000 | Float shader constants (256 × float4) |
| 1 | 0x4800 | Fetch constants (texture/vertex descriptors, 24 bytes each) |
| 2 | 0x4900 | Boolean shader constants |
| 3 | 0x4908 | Loop constants |
| 4 | 0x2000 | General GPU configuration registers |
Key configuration registers include `RBBM_STATUS`, `COHER_STATUS_HOST` (0x0578), `RB_COLOR_INFO` / `RB_DEPTH_INFO` (0x0D00 range), `PA_SC_WINDOW_OFFSET` (0x2000 range), `VGT_DRAW_INITIATOR` (0x2100 range), and `SQ_PROGRAM_CNTL` (0x4000 range).
### Shader microcode format
Xenos microcode closely follows the **AMD R600 ISA** (publicly documented). Three instruction types exist:
- **Control Flow (CF):** 64 bits. Controls execution flow, initiates fetch/export operations.
- **ALU:** 64 bits. 5-slot VLIW (vector + scalar). Grouped into ALU clauses.
- **Fetch:** 96 bits (3 DWORDs). Vertex and texture fetch operations.
Shader programs are unified — the same microcode format serves both vertex and pixel shaders. The hardware dynamically assigns processors to VS/PS workloads. Xenia's `src/xenia/gpu/ucode.h` defines the complete microcode structures; `shader_translator.cc` translates them to host GPU IR.
### Memory export (MEMEXPORT)
**MEMEXPORT** is Xenos-specific: shaders write arbitrary data to system memory addresses, enabling **GPGPU compute** before compute shaders existed. Vertex shaders export computed data (particles, physics, procedural geometry) to memory via special export registers. The CPU can read this data after GPU synchronization.
### Texture formats
Xenos supports standard D3D9 formats plus Xbox 360 extensions. Textures use **tiled (Morton/Z-order swizzled)** layout by default for optimal cache performance; linear layout requires explicit specification. Maximum dimensions are **8192×8192** (2D).
Xbox 360only compressed formats include **DXT3A** (4×4, 64 bits, scalar), **DXT5A** (4×4, 64 bits, two-endpoint scalar), **DXN** (128 bits, two-channel DXT5A), and **CTX1** (4×4, 64 bits, shared-index). Color render target formats range from `k_8_8_8_8` through `k_2_10_10_10_FLOAT` (7e3 HDR) to `k_32_32_FLOAT`.
---
## 3. XDVDFS: the Xbox DVD file system on game discs
Xbox 360 game discs use a proprietary file system called **XDVDFS** (also GDFX or XISO) — not ISO 9660 or UDF. The sector size is **2048 bytes (0x800)**. Directory entries form a **binary search tree** rather than a linear listing.
### Volume descriptor at sector 32
The volume descriptor occupies sectors 3233. On a raw XISO image, it begins at byte offset **0x10000** from the game partition start:
| Offset | Size | Type | Content |
|--------|------|------|---------|
| 0x000 | 0x14 | char[20] | Magic: `MICROSOFT*XBOX*MEDIA` |
| 0x014 | 0x04 | uint32_le | Root directory table sector |
| 0x018 | 0x04 | uint32_le | Root directory table size (bytes) |
| 0x01C | 0x08 | uint64_le | Timestamp (Win32 FILETIME) |
| 0x024 | 0x7C8 | — | Zero padding |
| 0x7EC | 0x14 | char[20] | Magic (repeated): `MICROSOFT*XBOX*MEDIA` |
### Directory entry structure (variable size, minimum 14 bytes)
| Offset | Size | Type | Field |
|--------|------|------|-------|
| 0x00 | 0x02 | uint16_le | Left subtree offset (in DWORDs from directory table start) |
| 0x02 | 0x02 | uint16_le | Right subtree offset (in DWORDs) |
| 0x04 | 0x04 | uint32_le | Starting sector of file data |
| 0x08 | 0x04 | uint32_le | File size in bytes |
| 0x0C | 0x01 | uint8 | Attributes (0x10=DIRECTORY, 0x20=ARCHIVE, 0x80=NORMAL) |
| 0x0D | 0x01 | uint8 | Filename length |
| 0x0E | var | char[] | Filename (padded to DWORD boundary with 0xFF) |
Subtree offsets of 0 indicate no child. Files occupy contiguous sectors. Subdirectories point to nested directory tables.
### Game disc geometry (XGD2 / XGD3)
| Format | Game Partition Offset | Capacity |
|--------|----------------------|----------|
| XGD2 (early 360) | **0x0FD90000** | ~6.8 GiB |
| XGD3 (2011+) | **0x02080000** | ~7.8 GiB |
All Xbox 360 discs are dual-layer DVD-DL. Security sectors on the outer ring use a challenge/response protocol: 23 entries encrypted with **RC4** (key derived by SHA-1 hashing a 44-byte block at security sector offset 1183), verified by RSA signatures.
---
## 4. STFS: secure transacted file system for saves and DLC
STFS packages contain downloadable content, save games, profiles, and XBLA titles stored on HDD or memory units. The format uses SHA-1 Merkle trees for integrity and RSA signatures for authentication. Block size is **0x1000 (4096 bytes)**, with hash tables interleaved every **0xAA (170)** data blocks.
### Header layout (canonical offsets from Free60)
**Magic bytes at offset 0x000 (4 bytes):**
| Magic | ASCII | Meaning |
|-------|-------|---------|
| 0x434F4E20 | `CON ` | Console-signed (saves, profiles) |
| 0x4C495645 | `LIVE` | Xbox Live Marketplace content |
| 0x50495253 | `PIRS` | Microsoft-signed read-only content |
**Metadata section:**
| Offset | Size | Field |
|--------|------|-------|
| 0x022C | 0x100 | License entries (16 × 0x10 bytes: int64 licenseID + int32 bits + int32 flags) |
| 0x032C | 0x14 | Header SHA-1 hash (covers 0x0344 through first hash table) |
| 0x0340 | 0x04 | Header size (uint32) |
| 0x0344 | 0x04 | **Content type** (uint32, see enum below) |
| 0x0348 | 0x04 | Metadata version |
| 0x034C | 0x08 | Content size (uint64) |
| 0x0354 | 0x04 | Media ID |
| 0x0358 | 0x04 | Version |
| 0x035C | 0x04 | Base version |
| 0x0360 | 0x04 | **Title ID** (e.g., 0x4D5307E6 for Halo 3) |
| 0x0364 | 0x01 | Platform (2=Xbox 360, 4=PC) |
| 0x0365 | 0x01 | Executable type |
| 0x0366 | 0x01 | Disc number |
| 0x0367 | 0x01 | Disc in set |
| 0x0368 | 0x04 | Save game ID |
| 0x036C | 0x05 | Console ID |
| 0x0371 | 0x08 | Profile ID |
| 0x0379 | 0x24 | **STFS Volume Descriptor** (36 bytes, see below) |
| 0x039D | 0x04 | Data file count |
| 0x03A1 | 0x08 | Data file combined size |
| 0x0411 | 0x900 | Display name (UTF-8, 18 locales × 0x80 bytes) |
| 0x0D11 | 0x900 | Display description |
| 0x1691 | 0x80 | Title name |
| 0x171A | 0x4000 | Thumbnail image (PNG, ≤16384 bytes) |
| 0x571A | 0x4000 | Title thumbnail image |
**Total header size (v1): 0x971A bytes.**
### STFS volume descriptor (36 bytes at offset 0x0379)
| Offset | Size | Field |
|--------|------|-------|
| 0x00 | 0x01 | Size (always 0x24) |
| 0x01 | 0x01 | Reserved |
| 0x02 | 0x01 | Block separation (bit 0 determines hash table spacing) |
| 0x03 | 0x02 | File table block count |
| 0x05 | 0x03 | File table block number (int24) |
| 0x08 | 0x14 | Top hash table hash (SHA-1) |
| 0x1C | 0x04 | Total allocated block count |
| 0x20 | 0x04 | Total unallocated block count |
### Hash table hierarchy
Each **hash entry is 24 bytes (0x18):** 20-byte SHA-1 digest + 1-byte status + 3-byte next-block number. Status values: **0x00** (unused), **0x40** (freed), **0x80** (used), **0xC0** (newly allocated).
- **Level 0:** 0xAA (170) entries, each covering one data block
- **Level 1:** 0xAA entries, each covering one L0 table — spans 170² = **28,900 blocks**
- **Level 2:** 0xAA entries, each covering one L1 table — spans 170³ = **4,913,000 blocks**
CON packages may maintain **dual hash tables** per level for transactional integrity. Block-to-file-offset conversion must account for interleaved hash table blocks:
```
FileOffset(block) = ((headerSize + 0xFFF) & 0xF000) + (adjustedBlock << 12)
```
where `adjustedBlock` adds 1 hash-table block per 0xAA data blocks, plus L1/L2 table blocks for larger packages.
### Content type enum (key values)
| Value | Type |
|-------|------|
| 0x0000001 | Saved Game |
| 0x0001000 | Xbox 360 Title |
| 0x0004000 | Installed Game |
| 0x0007000 | Game on Demand |
| 0x0010000 | Profile |
| 0x0040000 | Cache File |
| 0x0080000 | Game Demo |
| 0x00D0000 | Arcade Title (XBLA) |
| 0x2000000 | Community Game |
### File listing entry (0x40 = 64 bytes each)
| Offset | Size | Field |
|--------|------|-------|
| 0x00 | 0x28 | Filename (null-padded, 40 chars max) |
| 0x28 | 0x01 | Flags: bits 05 = name length, bit 6 = consecutive blocks, bit 7 = is directory |
| 0x29 | 0x03 | Allocated block count (int24 LE) |
| 0x2C | 0x03 | Allocated block count copy |
| 0x2F | 0x03 | Starting block number (int24 LE) |
| 0x32 | 0x02 | Path indicator (0xFFFF = root; else parent entry index) |
| 0x34 | 0x04 | File size (uint32 BE) |
| 0x38 | 0x04 | Update timestamp (FAT format) |
| 0x3C | 0x04 | Access timestamp (FAT format) |
---
## 5. XEX2: the Xbox executable container format
XEX2 is an encrypted, compressed wrapper around a standard PE32 image. It is the mandatory packaging format for all Xbox 360 executables.
### IMAGE_XEX_HEADER (0x18 bytes)
```c
struct IMAGE_XEX_HEADER {
char Magic[4]; // +0x00 "XEX2" = 0x58455832
uint32_t ModuleFlags; // +0x04 See flag bits
uint32_t SizeOfHeaders; // +0x08 Offset to PE data
uint32_t SizeOfDiscardableHeaders; // +0x0C Reserved
uint32_t SecurityInfo; // +0x10 File offset → XEX_SECURITY_INFO
uint32_t HeaderDirectoryEntryCount; // +0x14 Number of optional headers
// IMAGE_XEX_DIRECTORY_ENTRY[] at +0x18
};
```
**Module flags (bitfield):** 0x0001=TITLE_PROCESS, 0x0002=TITLE_IMPORTS, 0x0004=DEBUGGER, 0x0008=DLL, 0x0010=PATCH, 0x0020=PATCH_FULL, 0x0040=PATCH_DELTA, 0x0080=USER_MODE.
**XEX format variants:**
| Magic | Hex | Minimum Kernel |
|-------|-----|---------------|
| `XEX2` | 0x58455832 | ≥ 1861 (retail) |
| `XEX1` | 0x58455831 | ≥ 1838 (beta) |
| `XEX%` | 0x58455825 | ≥ 1746 |
| `XEX-` | 0x5845582D | ≥ 1640 |
| `XEX0` | 0x58455830 | ≥ 1332 |
### Optional header directory (at +0x18)
Each entry is 8 bytes: **uint32 Key** + **uint32 Value**. The low byte of Key encodes the data format:
- `Key & 0xFF == 0x00`: Value is an immediate flag
- `Key & 0xFF == 0x01`: Value is an immediate DWORD
- `Key & 0xFF == 0xFF`: Value is file offset to size-prefixed struct
- Other: Value is file offset; low byte × 4 = struct size
**Complete optional header key table:**
| Key ID | Name | Data Type |
|--------|------|-----------|
| 0x000002FF | Section Table | SizedStruct |
| 0x000003FF | File Data Descriptor (compression/encryption) | SizedStruct |
| 0x00000405 | Patch File Base Reference | Fixed 0x14 |
| 0x000005FF | Delta Patch Descriptor | SizedStruct |
| 0x000103FF | **Import Libraries** | SizedStruct |
| 0x00010001 | Original Base Address | ULONG |
| 0x00010100 | **Entry Point** (VA) | Flag |
| 0x00010201 | PE Base Address | ULONG |
| 0x000183FF | Original PE Module Name | String |
| 0x000200FF | Static Libraries / Build Versions | SizedStruct |
| 0x00020104 | TLS Data (16 bytes) | Struct |
| 0x00020200 | Default Stack Size | Flag |
| 0x00020301 | Default FS Cache Size | ULONG |
| 0x00020401 | Default Heap Size | ULONG |
| 0x00030000 | System Flags / Privileges | Flag |
| 0x00040006 | **Execution ID** (Title ID, version — 24 bytes) | Struct |
| 0x00040310 | Game Ratings (64 bytes) | Fixed 0x40 |
| 0x00040404 | LAN Key (16 bytes) | Fixed 0x10 |
| 0x000405FF | Xbox 360 Logo | SizedStruct |
| 0x000406FF | Multi-Disc Media IDs | SizedStruct |
| 0x00E10402 | PE Exports (IMAGE_DATA_DIRECTORY) | Struct |
### XEX_SECURITY_INFO structure
Located at the file offset stored in `SecurityInfo` (+0x10):
```c
struct XEX_SECURITY_INFO {
uint32_t Size; // +0x000
uint32_t ImageSize; // +0x004
HV_IMAGE_INFO ImageInfo; // +0x008 (0x174 bytes, see below)
uint32_t AllowedMediaTypes; // +0x17C
uint32_t PageDescriptorCount; // +0x180
HV_PAGE_INFO PageDescriptors[]; // +0x184 (variable, 0x18 bytes each)
};
```
**HV_IMAGE_INFO (0x174 bytes at SecurityInfo+0x08):**
| Offset | Size | Field |
|--------|------|-------|
| 0x000 | 0x100 | RSA-2048 signature (256 bytes) |
| 0x100 | 0x04 | Info size |
| 0x104 | 0x04 | Image flags |
| 0x108 | 0x04 | Virtual load address |
| 0x10C | 0x14 | Image SHA-1 hash |
| 0x120 | 0x04 | Import table count |
| 0x124 | 0x14 | Import table SHA-1 digest |
| 0x138 | 0x10 | Media ID (16 bytes) |
| **0x148** | **0x10** | **Encrypted AES-128 session key** |
| 0x158 | 0x04 | Export table VA |
| 0x15C | 0x14 | Header SHA-1 hash |
| 0x170 | 0x04 | Game region flags |
**HV_PAGE_INFO (0x18 bytes each):**
```c
struct HV_PAGE_INFO {
uint32_t PageDescription; // +0x00 Bits [31:28]=Info(type), [27:0]=Size(page count)
uint8_t DataDigest[0x14]; // +0x04 SHA-1 hash of page data
};
// Info values: 1=CODE, 2=DATA, 3=READONLY_DATA
```
### Execution ID (24 bytes at optional header 0x00040006)
```c
struct XEX_EXECUTION_ID {
uint32_t MediaID; // +0x00
uint32_t Version; // +0x04 Major(4):Minor(4):Build(16):QFE(8)
uint32_t BaseVersion; // +0x08
uint32_t TitleID; // +0x0C e.g. 0x4D5307E6 (Halo 3)
uint8_t Platform; // +0x10
uint8_t ExecutableType; // +0x11
uint8_t DiscNum; // +0x12
uint8_t DiscsInSet; // +0x13
uint32_t SaveGameID; // +0x14
};
```
### Encryption keys and decryption flow
```
XEX2 Retail Key (AES-128):
20 B1 85 A5 9D 28 FD C3 40 58 3F BB 08 96 BF 91
XEX2 Devkit Key (AES-128):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (all zeros)
```
**Decryption procedure:**
1. Read 16-byte encrypted session key from `HV_IMAGE_INFO.ImageKey` (offset +0x148)
2. Decrypt with **AES-128-ECB** using the retail (or devkit) key → per-file session key
3. Decrypt the PE payload (starting at file offset `SizeOfHeaders`) using **AES-128-CBC** with the session key (IV = all zeros initially)
4. If encrypted flag not set in File Data Descriptor, skip decryption
### Compression
The **File Data Descriptor** (key 0x000003FF) specifies compression:
| Format Value | Name | Method |
|-------------|------|--------|
| 0x0000 | NONE | Uncompressed |
| 0x0001 | RAW | Block-based (DataSize + ZeroSize pairs, 8 bytes each) |
| 0x0002 | COMPRESSED | LZX-based with SHA-1 per block (window typically 0x8000 or 0x20000) |
| 0x0003 | DELTA_COMPRESSED | Patch format |
### Import system
Imports are **ordinal-only**. The import descriptor (key 0x000103FF) contains:
```c
struct XEX_IMPORT_DESCRIPTOR {
uint32_t Size; // +0x00
uint32_t NameTableSize; // +0x04
uint32_t ModuleCount; // +0x08
// char NameTable[] (null-separated library names)
// XEX_IMPORT_TABLE[] (one per module)
};
```
Each per-library table contains a module index, version info, import count, and an array of thunk virtual addresses. Bit 24 of each import record distinguishes function imports (patched as branch stubs) from variable imports (address written directly).
---
## 6. Kernel and operating system internals
The Xbox 360 runs a modified NT kernel (`xboxkrnl.exe`) under a **hypervisor (HV)** — roughly 128 KB of code operating in PowerPC real mode with highest privilege. The HV enforces **W^X** (write XOR execute) across all memory, manages page tables via software TLB, and encrypts all executable pages in RAM. Games run in kernel mode with virtual addressing; there is effectively one "process" at a time.
### Kernel exports (by ordinal)
Exports are ordinal-only. Selected confirmed ordinals from Xenia's `xboxkrnl_table.inc`:
| Ordinal | Export |
|---------|--------|
| 0x001 | DbgBreakPoint |
| 0x003 | DbgPrint |
| 0x00E | ExEventObjectType |
| 0x0CF | NtClose |
| 0x0D0 | NtCreateDirectoryObject |
| 0x0D1 | NtCreateEvent |
| 0x0D2 | NtCreateFile |
| 0x0D3 | NtCreateIoCompletion |
| 0x0D4 | NtCreateMutant |
| 0x0D5 | NtCreateSemaphore |
| 0x0D7 | NtCreateTimer |
| 0x0D8 | NtDeleteFile |
| 0x156 | XboxHardwareInfo (variable, 16 bytes) |
| 0x157 | XboxKrnlBaseVersion |
| 0x158 | XboxKrnlVersion |
| 0x159 | XeCryptAesKey |
| 0x15A | XeCryptAesEcb |
| 0x15B | XeCryptAesCbc |
| 0x164 | XeCryptBnQwBeSigCreate |
| 0x166 | XeCryptBnQwBeSigVerify |
| 0x16D | XeCryptBnQwNeRsaPubCrypt |
The full table contains **~900+ exports**. Additional families include Ex* (executive), Ke* (kernel core), Rtl* (runtime), Mm* (memory manager), Ob* (object manager), Xex* (module loading), and Vd* (video). The authoritative reference is Xenia's `xboxkrnl_table.inc`.
### Hypervisor syscall mechanism
The PowerPC `sc` instruction triggers a syscall interrupt. The CPU enters real mode and vectors to **0x00000C00**. Syscall number is in **r0**, arguments in **r3r12**, return value in **r3**.
The HV dispatcher (from the 4532 kernel vulnerability disclosure):
```asm
0x13D8: cmplwi %r0, 0x61 ; max syscall = 0x61 (97)
0x13DC: bge illegal_syscall
0x13F0: rldicr %r1, %r0, 2, 61 ; offset = r0 * 4
0x13F4: lwz %r4, 0x1F68(%r1); load handler from table at 0x1F68
0x1414: blrl ; call handler
```
**Key HV syscalls:**
| Number | Name |
|--------|------|
| 0x00 | HvxGetVersions |
| 0x02 | HvxMemoryProtect |
| 0x07 | HvxGetSpecialPurposeRegister |
| 0x08 | HvxSetSpecialPurposeRegister |
| 0x10 | HvxDvdAuthBegin |
| 0x16 | HvxXexLoadImage |
| 0x17 | HvxXexUnloadImage |
| 0x19 | HvxXexGetProcAddress |
| 0x1A | HvxXexGetModuleHandle |
| 0x25 | HvxXexVerifyImage |
| 0x40 | HvxKeysInitialize |
| 0x41 | HvxKeysExGetKey |
| 0x45 | HvxKeysExGetConsoleId |
| 0x46 | HvxKeysSetKeyVault |
### Thread local storage
**r13** points to the KPCR (Kernel Processor Control Region) in kernel mode. **r2** is the user-mode TLS base pointer. The TEB inherits NT structure with key fields at: +0x02C (ThreadLocalStoragePointer), +0x030 (PEB pointer), +0xE10 (TlsSlots[64]).
---
## 7. Xbox 360 Direct3D: a thin layer over GPU command buffers
The Xbox 360 D3D implementation is a **bare-bones wrapper** that writes PM4 packets directly into a GPU ring buffer — no abstracted driver stack. Key differences from PC D3D9 include direct memory control via XGraphics (`XGSetTextureHeader`, `XGSetVertexBufferHeader`), eDRAM-centric rendering requiring explicit resolve operations, and extensions like `vfetch`, `tfetch`, and MEMEXPORT.
### Ring buffer architecture
The Xenos processes commands from a circular buffer in system memory defined by:
- **Base pointer:** Physical start address of ring buffer
- **Write pointer:** CPU advances after writing PM4 packets
- **Read pointer:** GPU advances as it consumes commands
- **Size:** Total buffer capacity
The GPU stalls when read would pass write. Secondary command lists dispatch via `PM4_INDIRECT_BUFFER` (0x3F), analogous to D3D12 command lists.
### Shader constant register mapping
Float constants load into GPU registers at base **0x4000** (256 × float4 = 1024 DWORDs for VS, extending into PS range). Fetch constants (texture/vertex descriptors) occupy base **0x4800** as 24-byte structures encoding buffer address, stride, format, and dimensions. Boolean constants pack at **0x4900** as 32-bit bitmasks. Loop constants sit at **0x4908**.
### CPU-to-GPU memory translation
In the **unified memory architecture**, CPU and GPU share the same 512 MB physical address space. Vertex/index buffer allocation simply returns a CPU-accessible virtual address that maps to the same physical memory the GPU reads. Fetch constants store the **physical address** of the buffer. No upload or copy is needed — the GPU reads directly from where the CPU wrote.
### Predicated tiling workflow
When eDRAM cannot hold the full framebuffer (e.g., 4× MSAA at 720p), D3D splits rendering into tiles. For each tile, the GPU **replays the entire command buffer** with hardware predication culling off-tile primitives. This is configured via `PM4_SET_BIN_BASE_OFFSET` (0x4B), `PM4_SET_BIN_MASK` (0x50), and `PM4_SET_BIN_SELECT` (0x51). After rendering each tile, a resolve operation copies eDRAM contents to main RAM, optionally downsampling MSAA.
---
## 8. XMA audio and XACT sound banks
### XMA2WAVEFORMATEX (52 bytes)
```
Offset Size Field Notes
0x00 2 wFormatTag 0x0166 (WAVE_FORMAT_XMA2)
0x02 2 nChannels Decoded channel count
0x04 4 nSamplesPerSec Decoded sample rate
0x08 4 nAvgBytesPerSec Encoder internal
0x0C 2 nBlockAlign channels × bitsPerSample / 8
0x0E 2 wBitsPerSample Always 16
0x10 2 cbSize Always 34
0x12 2 NumStreams 1 or 2 channels per stream
0x14 4 ChannelMask SPEAKER_xxx flags
0x18 4 SamplesEncoded Total decoded PCM samples
0x1C 4 BytesPerBlock XMA block size
0x20 4 PlayBegin First valid decoded sample
0x24 4 PlayLength Valid audio length
0x28 4 LoopBegin Loop start (decoded samples)
0x2C 4 LoopLength Loop length
0x30 1 LoopCount 255=infinite, 254=max finite
0x31 1 EncoderVersion ≥3 for XMA2
0x32 2 BlockCount XMA blocks in file
```
### XMA packet structure (2048 bytes, big-endian)
```
Bits 0-5: FrameCount (6 bits) Frames beginning in this packet
Bits 6-20: FrameOffsetInBits (15 bits) Bit offset to first complete frame
Bits 21-23: PacketMetaData (3 bits) Always 1 for XMA2
Bits 24-31: PacketSkipCount (8 bits) Other-stream packets to skip
Bytes 4-2047: Encoded XMA data (2044 bytes)
```
Key constants: **XMA_BYTES_PER_PACKET = 2048**, **XMA_SAMPLES_PER_FRAME = 512**, **XMA_SAMPLES_PER_SUBFRAME = 128**. Supported sample rates: 24000, 32000, 44100, 48000 Hz.
### Hardware XMA decoder at 0x7FEA0000
The Southbridge chip provides a hardware XMA decoder accessed via MMIO at virtual address **0x7FEA0000** (64 KB register space). Up to **320 hardware contexts** can be active simultaneously. Each `XMA_CONTEXT_DATA` is 64 bytes (16 DWORDs, big-endian) containing input/output buffer pointers, loop parameters, sample rate, stereo flag, and read/write offsets packed into bitfields.
### XACT wave bank (XWB) format
Header magic: **"WBND"** (LE) = **0x444E4257**. The 12-byte header is followed by a segment table (5 entries × 8 bytes: offset + length) pointing to Bank Data, Entry Metadata, Seek Tables, Entry Names, and Wave Data.
Bank Data flags: `FLAGS_ENTRYNAMES = 0x00010000`, `FLAGS_COMPACT = 0x00020000`, `FLAGS_SEEKTABLES = 0x00080000`.
### XACT sound bank (XSB) format
Header magic: **"SDBK"** (LE). The header contains tool/format version, platform byte (0=PC, 2=Xbox), counts of simple/complex cues, wave banks, and sounds, followed by offset tables for cue data, sound entries, variation tables, and wave bank name references. Sound entries are variable-sized: simple sounds (11 bytes: flags + category + volume + track index + wave bank index) vs complex sounds with clip arrays.
---
## 9. XInput gamepad state and USB protocol
### XINPUT_GAMEPAD (12 bytes at XINPUT_STATE+0x04)
```c
struct XINPUT_GAMEPAD {
uint16_t wButtons; // +0x00 Bitmask
uint8_t bLeftTrigger; // +0x02 0255
uint8_t bRightTrigger; // +0x03 0255
int16_t sThumbLX; // +0x04 32768 to 32767
int16_t sThumbLY; // +0x06
int16_t sThumbRX; // +0x08
int16_t sThumbRY; // +0x0A
};
```
**Button flags:**
```
DPAD_UP=0x0001 DPAD_DOWN=0x0002 DPAD_LEFT=0x0004 DPAD_RIGHT=0x0008
START=0x0010 BACK=0x0020 LEFT_THUMB=0x0040 RIGHT_THUMB=0x0080
LB=0x0100 RB=0x0200 A=0x1000 B=0x2000
X=0x4000 Y=0x8000
```
Dead zones: **LEFT_THUMB=7849**, **RIGHT_THUMB=8689**, **TRIGGER_THRESHOLD=30**.
The Xbox 360 controller (VID 0x045E, PID 0x028E) uses **vendor-specific USB class 0xFF** — not standard HID. Interface 0 returns 20-byte input reports at **250 Hz** (4ms interval). Rumble output is an 8-byte report with large motor speed at byte 3 and small motor speed at byte 4.
---
## 10. XNet networking with Winsock-like semantics
Xbox 360 networking uses `xam.xex` exports wrapping a Winsock-like API with mandatory caller-ID parameters. All `NetDll_*` functions take a first argument specifying caller type (e.g., `XNCALLER_SYSAPP`).
Key function ordinals from `xam_table.inc`: `NetDll_XNetStartup` (0x33), `NetDll_XNetCleanup` (0x34), `NetDll_XNetRandom` (0x35), `NetDll_XNetCreateKey` (0x36), `NetDll_XNetXnAddrToInAddr` (0x39).
**XNADDR** is a 36-byte structure combining IP, MAC, and Xbox Live identity. XNet provides built-in IPsec-like encryption for peer-to-peer sessions via `XNetCreateKey`/`XNetRegisterKey`. Xbox Live uses TLS 1.2based security; detailed packet structures remain proprietary.
---
## 11. Decompilation and disassembly workflow
### Ghidra with XEXLoaderWV
**XEXLoaderWV** (by Warranty Voider, `github.com/zeroKilo/XEXLoaderWV`) loads XEX files directly into Ghidra with decryption/decompression, PDB support via MSDIA, and correct base address mapping. Set processor to `PowerPC:BE:32:default`. The loader handles both retail and devkit encryption. **Limitation:** Ghidra's PPC module does not fully support VMX-128's 7-bit register encoding — extended vector instructions may disassemble incorrectly.
### IDA Pro with idaxex
**idaxex** (by emoose, `github.com/emoose/idaxex`) supports XEX1/XEX2, all encryption variants, auto-names kernel/XAM imports, and passes CodeView info for PDB loading. Pair with the **PPCAltivec plugin** (`github.com/hayleyxyz/PPC-Altivec-IDA`) for VMX instruction support. The `xkelib.til` type library provides Xbox 360 SDK type definitions.
### Xenia as dynamic analysis platform
Xenia provides GPU trace capture (**F4** during gameplay), continuous stream logging (`--trace_gpu_stream`), and a trace viewer (`xe-gpu-trace-viewer`) for inspecting draw calls, register state, and shader microcode. Shader dumps (`--dump_shaders=path/`) output both translated host shaders and original Xenos microcode. Key debug flags:
```
--debug --log_level=3 --break_on_start=true --trace_gpu_stream=true
```
### PowerPC disassembly patterns
**Function prologue (Microsoft Xbox 360 compiler):**
```asm
mflr r0 ; Save return address
stw r30, -8(r1) ; Save nonvolatile registers into red zone
stw r31, -4(r1)
stw r0, -0xC(r1) ; Save LR on stack
stwu r1, -0x50(r1) ; Allocate frame atomically
```
**Function epilogue:**
```asm
lwz r0, 0x44(r1) ; Restore saved LR
lwz r30, 0x48(r1) ; Restore nonvolatiles
lwz r31, 0x4C(r1)
mtlr r0
addi r1, r1, 0x50 ; Deallocate frame
blr ; Return
```
**Import thunk stub (3+ instructions):**
```asm
lis r11, 0x8200 ; Upper 16 bits of IAT entry
ori r11, r11, 0x1234; Lower 16 bits
lwz r11, 0(r11) ; Load resolved function address
mtctr r11
bctr ; Indirect branch to import
```
**Register conventions:** r0 = scratch/LR only, r1 = stack pointer, r2 = TOC, r3 = return value / arg1, r4r10 = args 28, r14r31 = nonvolatile (callee-saved). Red zone below SP is 232 bytes.
### Recompilation tools
**XenonRecomp** (`github.com/hedge-dev/XenonRecomp`) performs static recompilation of Xbox 360 PPC code to native x86-64 C++. **XenosRecomp** (`github.com/hedge-dev/XenosRecomp`) translates Xenos GPU shaders to HLSL for D3D12/Vulkan, using function boundary analysis from `.pdata` exception directory entries.
---
## 12. Encryption and security architecture
### eFUSE-based per-console keys
Each Xbox 360 CPU contains **768 one-time-programmable eFuse bits** encoding a unique **16-byte CPU Key** (fusesets 3+5 concatenated with 4+6), update sequence counters (lockdown value preventing downgrade), and devkit/retail flags. The CPU Key encrypts the **KeyVault** — the master store for all per-console cryptographic material.
### Memory encryption
The HV implements **per-cache-line (128-byte) AES encryption** with four access pathways:
| Pathway | Protection | Use |
|---------|-----------|-----|
| 0 | None | Raw/unprotected memory |
| 1 | AES + CRC integrity | HV code and data |
| 2 | CPU SoC internal | Boot ROM, SRAM, eFuses (HV-only) |
| 3 | AES only | Game/kernel executable pages |
Encryption keys change every boot (hardware RNG), incorporating per-page 10-bit whitening values. This prevents cold-boot replay attacks.
### XEX key derivation chain
The HV derives the XEX2 decryption key via **HMAC-SHA-1** using an 8-byte `gCpuSecurityKey` (read from MMIO `0x80000200_000250B8` during init), the 1BL public key (0x110 bytes), 1BL encryption key (0x10 bytes), 1BL salt (10 bytes), and a static 0x590-byte key buffer containing the PIRS verification public key, roamable obfuscation key root, and XeMACS authentication public key.
### Content license verification
STFS packages bind licenses to console IDs or Xbox Live accounts (XUIDs). CON packages are signed with the console's private key from the KeyVault; LIVE/PIRS packages use Microsoft's public key. The kernel verifies the RSA signature over the header SHA-1 hash before granting access. The SHA-1 Merkle tree (L0 → L1 → L2 hash tables) ensures data block integrity from individual 4096-byte blocks up to the RSA-signed root hash.
---
## 13. Complete virtual address space and MMIO reference
### Virtual address map
| Range | Purpose |
|-------|---------|
| `0x00000000``0x0000FFFF` | Null guard / reserved |
| `0x00010000``0x3FFFFFFF` | User/title virtual memory (heap, stacks) |
| `0x40000000``0x7FE9FFFF` | Extended title space (physical memory mapping) |
| `0x7FEA0000``0x7FEAFFFF` | **XMA decoder MMIO** |
| `0x7FFF0000``0x7FFFFFFF` | Guard pages |
| `0x80000000``0x8FFFFFFF` | Kernel virtual address space |
| `0x82000000` | **Typical game XEX load base** |
| `0x90000000``0x9FFFFFFF` | Physical memory identity map (uncached) |
| `0xA0000000``0xBFFFFFFF` | Physical memory alternate mappings |
| `0xC0000000``0xDFFFFFFF` | Additional physical mapping regions |
| `0xE0000000``0xFFFFFFFF` | MMIO / device register space |
### MMIO register blocks
| Physical Address | Size | Device |
|-----------------|------|--------|
| `0x7FEA0000` | 64 KB | XMA audio decoder (context array, control registers) |
| `0xC0000000` | ~1 MB | PCI / Southbridge configuration |
| `0xC8000000` | Region | NAND flash controller (SFCX) |
| `0xEA001000` | ~4 KB | Southbridge I/O (SATA, USB) |
| `0xEA001080` | 16 B | SMC write FIFO (System Management Controller) |
| `0xEA001090` | 16 B | SMC read FIFO |
| `0xEC800000` | ~256 KB+ | **Xenos GPU** (command processor, shader regs, display) |
## Conclusion: a roadmap for re-implementation
Three insights emerge from this comprehensive analysis that directly inform porting strategy. First, the Xenon's **in-order, VMX-128-heavy execution model** means game code is heavily hand-optimized for specific pipeline timings and the extended 128-register vector file — naïve PPC-to-x64 translation loses these optimizations, making static recompilation tools like XenonRecomp essential starting points. Second, the GPU's **PM4 command stream is fully documented** through Xenia's source, and the shader ISA's kinship with AMD R600 means public ISA manuals cover ~90% of the microcode format, with XenosRecomp handling the translation to modern HLSL. Third, every container format (XEX, STFS, XDVDFS, XWB/XSB) is byte-level documented by the community, enabling complete asset extraction pipelines. The practical path forward combines Xenia's runtime infrastructure for behavioral validation, static recompilation for CPU code, shader translation for GPU code, and format-level extraction for game assets — all grounded in the binary specifications documented above.