aboutsummaryrefslogtreecommitdiffstats
path: root/psp_out/rw_diff.py
diff options
context:
space:
mode:
authorPeter Geissler <peter@haxx.in>2026-09-22 11:14:57 +0200
committerPeter Geissler <peter@haxx.in>2026-09-22 11:14:57 +0200
commit649992b26c75eb13ace40c6eec499895a69a1132 (patch)
tree09bfb3ac77a3cc3462d9e2972a678da246cefeb4 /psp_out/rw_diff.py
downloadamd-psp-re-649992b26c75eb13ace40c6eec499895a69a1132.tar.gz
amd-psp-re-649992b26c75eb13ace40c6eec499895a69a1132.tar.xz
amd-psp-re-649992b26c75eb13ace40c6eec499895a69a1132.zip
Initial import: AMD PSP reverse engineering, emulator and vulnerability research
Split out of a tinygrad working tree, where all of this lived untracked. tinygrad remains a dependency for hardware-facing scripts only. Contents: psp_emu/ Unicorn-based PSP emulator that boots the real signed firmware from the ARM reset vector: sOS -> SYS_DRV -> HDCP/DTM/RAS TAs, with a CCP crypto device model faithful enough to run the firmware's own drivers (RSA-PSS/SHA-256 container verification passes 5/5 with 5/5 negatives rejected). A simulated host drives the real mailbox/ring path through to TA_InvokeCommandEntryPoint. psp_out/ Static analysis: six PSP modules fully named (asd 1562, sys_drv 1141, sos 527, ras 119, hdcp 109, dtm 14) plus SMU 1033, a cross-version diffing pipeline over 34+ builds, per-handler annotated analysis and ~125 findings documents. Deliberately not tracked: AMD firmware images, the Hex-Rays decompilation derived from them, and IDA databases. data/MANIFEST.sha256 pins the SHA-256 of all 301 blobs results were derived from, so findings remain traceable to their inputs without redistributing AMD code. 6 MB tracked instead of 315 MB. Verified from the new location: test_smoke 5/5, ccp_selftest 11/11, verify_real_image 5/5 + 5/5 negatives, fuzz_ta_invoke controls passing and host-driven TA invoke working (0.73s per invoke).
Diffstat (limited to 'psp_out/rw_diff.py')
-rw-r--r--psp_out/rw_diff.py22
1 files changed, 22 insertions, 0 deletions
diff --git a/psp_out/rw_diff.py b/psp_out/rw_diff.py
new file mode 100644
index 0000000..2454fd3
--- /dev/null
+++ b/psp_out/rw_diff.py
@@ -0,0 +1,22 @@
+import ctypes
+from tinygrad import Device
+from tinygrad.runtime.autogen.am import am
+d=Device["AMD"]; adev=d.iface.dev_impl; psp=adev.psp
+SZ=ctypes.sizeof(am.struct_psp_gfx_cmd_resp); C=28
+def run(cid,words):
+ adev.vram.view(psp.cmd_paddr,SZ)[:]=b"\x00"*SZ
+ c=am.struct_psp_gfx_cmd_resp(cmd_id=cid); buf=bytearray(memoryview(c).cast('B'))
+ for i,v in words.items(): buf[C+i*4:C+4+i*4]=int(v&0xFFFFFFFF).to_bytes(4,'little')
+ adev.vram.view(psp.cmd_paddr,SZ)[:]=bytes(buf)
+ before=bytes(buf)
+ try: psp._ring_submit(am.struct_psp_gfx_cmd_resp.from_buffer_copy(bytes(buf)))
+ except Exception: pass
+ after=bytes(adev.vram.view(psp.cmd_paddr,SZ)[:])
+ return before,after
+for label,words in (("READ idx=5",{0:5,1:0,2:1}),("WRITE idx=5 magic",{0:5,1:0xA5A5F00D,2:0}),("READ idx=3",{0:3,1:0,2:1})):
+ b,a=run(0x0d,words)
+ diffs=[(o,int.from_bytes(b[o:o+4],'little'),int.from_bytes(a[o:o+4],'little')) for o in range(0,SZ,4)
+ if b[o:o+4]!=a[o:o+4]]
+ print(f"\ncmd 0x0d {label}: {len(diffs)} words changed by the PSP")
+ for o,x,y in diffs: print(f" +{o:#05x} {x:#010x} -> {y:#010x}")
+print("\nsOS alive:",psp.is_sos_alive())