Skip to content

Instantly share code, notes, and snippets.

@rmuxnet
Created March 19, 2026 11:54
Show Gist options
  • Select an option

  • Save rmuxnet/fff41726596d7da0ba7196e099a8e8de to your computer and use it in GitHub Desktop.

Select an option

Save rmuxnet/fff41726596d7da0ba7196e099a8e8de to your computer and use it in GitHub Desktop.
ps4 icc nvs
"""
ps4_icc_nvs.py
--------------
NVS directory sweep via ICC major 0x01, minor 0x00.
query_nvs_entry(fd, idx) query a single NVS index (0x00-0xFF)
sweep_nvs() sweep all 256 entries, return populated list
print_nvs_directory() formatted table with recovery path notes
Hardware: PS4 Fat (Aeolia CXD90025G)
Kernel: Linux 6.18.18-Strawberry-ThinLTO-LTS+ (CachyOS x86_64)
DEVICE PERMISSIONS
------------------
If /dev/icc does not exist or you get PermissionError:
cat /proc/devices | grep icc
sudo mknod /dev/icc c <major> 0
sudo chmod 666 /dev/icc
Permanent udev rule (survives reboots):
echo 'KERNEL=="icc", MODE="0666"' | sudo tee /etc/udev/rules.d/99-ps4-icc.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
ARCHITECTURE NOTE
-----------------
The NVS accessed here is syscon's internal flash storage -- distinct from the
EMC-managed sflash NVS areas (csarea, dsarea, osarea, pdarea). Syscon runs ICC
over SPI (SPI + interrupt line) and exposes its NVS index through major 0x01.
WHAT CAN BE DETERMINED (no auth)
----------------------------------
- Which indices 0x00-0xFF are populated
- Type code and inferred size of each entry
- That specific entries exist (e.g. Wi-Fi MAC at 0x02, serial at 0x04)
WHAT CANNOT BE DETERMINED (RSA-gated)
---------------------------------------
Values are gated behind RSA authentication (uareq1 / uareq2 on EMC UART).
Exhaustive ICC probing confirmed no bypass:
256 x 256 payload sweep, all minors, 7 format strategies,
pre-auth sequence attempts -- zero value bytes returned.
ALTERNATIVE VALUE RECOVERY (no auth required)
----------------------------------------------
Wi-Fi MAC /sys/class/net/mlan0/address
Ethernet MAC /sys/class/net/enp0s20f1/address
BD address stale buffer from 0x02/0x01 (see ps4_icc_sysinfo.py)
Serial EMC UART 'dsarea' after RSA auth (uareq1/uareq2)
NVS TYPE CODES
--------------
0x00 u8 scalar (1 byte)
0x01 boolean flag (1 byte)
0x02 u16 little-endian (2 bytes)
0x06 6-byte blob (MAC / BD address format)
0x21 33-byte string (32 ASCII chars + null terminator)
KNOWN INDEX MAP (full 0x00-0xFF sweep, Aeolia Fat unit)
---------------------------------------------------------
0x01 0x00 1B unknown scalar
0x02 0x06 6B Wi-Fi MAC address
0x03 0x00 1B unknown scalar
0x04 0x21 33B serial number (32 ASCII + null)
0x05 0x01 1B boolean flag
0x06 0x00 1B unknown scalar
0x07 0x00 1B unknown scalar
0x08 0x00 1B unknown scalar
0x09 0x01 1B boolean flag
0x0A 0x02 2B unknown u16
0x0B 0x01 1B boolean flag
0x10 0x01 1B boolean flag
0x11 0x00 1B unknown scalar
0x8C 0x00 1B factory calibration
0x8D 0x00 1B factory calibration
(all other indices return empty / status 0x02)
"""
from ps4_icc_core import call_icc, ICCError
NVS_TYPES = {
0x00: ('u8 scalar', 1),
0x01: ('boolean flag', 1),
0x02: ('u16 little-endian', 2),
0x06: ('6-byte blob (MAC/BD)', 6),
0x21: ('33-byte string (serial)', 33),
}
KNOWN_NVS_ENTRIES = {
0x01: 'unknown scalar',
0x02: 'Wi-Fi MAC address',
0x03: 'unknown scalar',
0x04: 'serial number (32 ASCII + null)',
0x05: 'boolean flag',
0x06: 'unknown scalar',
0x07: 'unknown scalar',
0x08: 'unknown scalar',
0x09: 'boolean flag',
0x0A: 'unknown u16',
0x0B: 'boolean flag',
0x10: 'boolean flag',
0x11: 'unknown scalar',
0x8C: 'factory calibration',
0x8D: 'factory calibration',
}
def query_nvs_entry(fd, idx):
reply = call_icc(fd, 0x01, 0x00, payload=bytes([idx & 0xFF]))
status = reply[0]
exists = (reply[2] == 0x01) if len(reply) > 2 else False
if status == 0x02 or not exists or status not in (0x00, 0x03):
return None
type_code = reply[3] if len(reply) > 3 else 0xFF
type_name, size = NVS_TYPES.get(type_code, (f'unknown(0x{type_code:02X})', '?'))
return {
'idx': idx,
'type_code': type_code,
'type_name': type_name,
'size': size,
'known_as': KNOWN_NVS_ENTRIES.get(idx, ''),
}
def sweep_nvs():
entries = []
try:
with open('/dev/icc', 'rb') as fd:
for idx in range(256):
try:
entry = query_nvs_entry(fd, idx)
if entry is not None:
entries.append(entry)
except ICCError:
pass
except FileNotFoundError:
raise ICCError("/dev/icc not found. Run: cat /proc/devices | grep icc -> sudo mknod /dev/icc c <major> 0")
except PermissionError:
raise ICCError("/dev/icc permission denied. Fix: sudo chmod 666 /dev/icc")
return entries
def print_nvs_directory():
print("NVS Directory (major 0x01 / minor 0x00)")
print("Values are RSA-gated -- only metadata returned without auth.")
print()
print(f" {'IDX':>5} {'TYPE':>6} {'SIZE':>5} {'TYPE NAME':<28} KNOWN AS")
print(f" {'-----':>5} {'------':>6} {'-----':>5} {'-'*28} {'-'*28}")
for e in sweep_nvs():
size_str = str(e['size']) if isinstance(e['size'], int) else e['size']
print(f" 0x{e['idx']:02X} 0x{e['type_code']:02X} {size_str:>5}B {e['type_name']:<28} {e['known_as']}")
print()
print("Alternative value recovery (no auth):")
print(" Wi-Fi MAC: cat /sys/class/net/mlan0/address")
print(" Ethernet MAC: cat /sys/class/net/enp0s20f1/address")
print(" BD address: stale buffer from 0x02/0x01 (see ps4_icc_sysinfo.py)")
print(" Serial: EMC UART 'dsarea' after uareq1/uareq2 auth")
if __name__ == '__main__':
print_nvs_directory()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment