aboutsummaryrefslogtreecommitdiffstats
path: root/hw/ring_wrap.py
blob: e74aead1ac70498aa4f2931b22cd164aab2c61ec (plain) (blame)
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
#!/usr/bin/env python3
"""Wrapping PSP ring submit — lifts the ~1008-invoke ceiling in our harness.

tinygrad's `_ring_submit` advances the write pointer monotonically and never wraps it against
`ring_size`, so after 1024 submits it writes past the ring allocation and the PSP stalls
(pass 84). Every fuzz in this audit was therefore capped at ~1000 invokes per boot.

This module monkeypatches a wrapping version onto the live PSP object. Import and call
`install(psp, adev)`; it returns a submit function with identical semantics plus wraparound.
"""
import ctypes
from tinygrad.helpers import wait_cond
import tinygrad.runtime.autogen.am.am as am

def install(psp, adev):
    frame_sz = ctypes.sizeof(am.struct_psp_gfx_rb_frame)
    step = frame_sz // 4
    def submit(cmd):
        # The write pointer itself must stay within the ring, not merely the byte offset:
        # letting it grow unbounded is what breaks at 1024 submits.
        wptr_max = psp.ring_size // 4
        prev = adev.reg(f"{psp.reg_pref}_67").read() % wptr_max
        byte_off = prev * 4
        msg = am.struct_psp_gfx_rb_frame(fence_value=prev + 1,
            cmd_buf_addr_lo=adev.paddr2mc(psp.cmd_paddr) & 0xFFFFFFFF,
            cmd_buf_addr_hi=adev.paddr2mc(psp.cmd_paddr) >> 32,
            fence_addr_lo=adev.paddr2mc(psp.fence_paddr) & 0xFFFFFFFF,
            fence_addr_hi=adev.paddr2mc(psp.fence_paddr) >> 32)
        adev.vram.view(psp.cmd_paddr, ctypes.sizeof(cmd))[:] = memoryview(cmd).cast('B')
        adev.vram.view(psp.ring_paddr + byte_off, ctypes.sizeof(msg))[:] = memoryview(msg).cast('B')
        adev.reg(f"{psp.reg_pref}_67").write((prev + step) % wptr_max)
        wait_cond(lambda: adev.vram.view(psp.fence_paddr, 4, 'I')[0], value=msg.fence_value,
                  msg="sOS ring not responding")
        return type(cmd).from_buffer(bytearray(adev.vram.view(psp.cmd_paddr, ctypes.sizeof(cmd))[:]))
    return submit