| Commit message (Collapse) | Author | Age |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Ported the last two prerequisites from gfx_v11_0.c: RS64 compute enable turns on
all four pipes together with MEC_HALT=0 (CP_MEC_RS64_CNTL 0x04000000 ->
0x3c000000), and kiq_init_register programs CP_MEC_DOORBELL_RANGE_LOWER/UPPER,
outside which the CP silently ignores doorbells.
Neither closed the gap. With the right slot, CP_HQD_ACTIVE=1, the scheduler
pointed at the queue, all pipes active, the MEC unhalted and the doorbell range
programmed, the queue still does not retire a NOP. The remaining candidate is the
MEC firmware's own per-pipe initialisation, since amdgpu loads MEC microcode per
pipe and the RS64 MEC likely only services pipes initialised at load time --
a substantially larger port.
Cost decides it: each failed attempt leaves an undequeueable HQD and GRBM_STATUS
0xa800302c that only a cold ATX cycle clears, and three have now been spent on
one open question. Stopping the thread.
The cheaper route is recorded for whoever picks it up: MAP_QUEUES sits at 0x3241c
in the validated PM4 table, inside the ~12 KB dispatcher sub_31360, and whether
any path from that label consults a privilege bit is a bounded static reverse
with no hardware cost and no power cycles.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Continuing round 7's blocker by reading amdgpu's KIQ bring-up and porting it.
Three concrete fixes. The KIQ slot was wrong, not merely unallocated:
amdgpu_gfx_kiq_acquire scans the queue bitmap downward requiring queue == 0, and
gfx11 has num_mec = 1, so ring->me = mec + 1 = 1. tinygrad hardcodes me=2/pipe=1,
a VF layout, which is exactly why round 7 saw CP_HQD_ACTIVE = 0. The real slot is
me=1 pipe=3 queue=0, reachable through setup_ring's ordinary path at idx=12 so
the MQD is still built by driver code -- CP_HQD_ACTIVE now reads 1. The HIQ
pointer encoding is RLC_CP_SCHEDULERS = (me<<5)|(pipe<<3)|queue|0x80 per
gfx_v11_0_kiq_setting. And because gfx11 is RS64, per-pipe enables live in
CP_MEC_RS64_CNTL rather than CP_MEC_CNTL; it read 0x04000000, only pipe0 active.
Still stalled: with the right slot, an active HQD, the scheduler pointed at it and
pipe3 enabled, CP_HQD_PQ_RPTR stays 0 while the doorbell and CP_HQD_PQ_WPTR_LO
both reach the queue. A pipe-0 queue on the identical code path retires the same
NOP, so the submission mechanism is sound and the gap is pipe-3 specific --
most likely the per-pipe HPD/EOP programming from amdgpu's compute resume.
CP_MEC_RS64_CNTL restored to its original value. MAP_QUEUES remains untested, but
the slot, scheduler encoding and pipe-enable register are now known and verified,
leaving one named piece.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Attempted to stand up a KIQ/HIQ ring to give round 6 its missing control.
Cleared two obstacles: tinygrad's mqd_paddr has 2+is_vf entries while
setup_ring(kiq_xcc=0) indexes 2 (fixed by appending an allocation so the
driver's own MQD code runs unchanged), and the KIQ's doorbell index 0 is
outside the apertures AM enables (re-pointed at MEC_RING0+4, an index the
compute probe had already rung).
Did not clear the third: CP_HQD_ACTIVE reads back 0 after setup_ring, so the CP
rejects the queue and no NOP retires. Root cause is that tinygrad's KIQ path is
VF-only and hardcodes me=2/pipe=1/queue=0, while amdgpu picks them dynamically
via amdgpu_gfx_kiq_acquire() and additionally needs the HPD EOP region, MEC pipe
enablement and the KIQ doorbell aperture -- an amdgpu KIQ port rather than a
patch.
The MAP_QUEUES chain therefore stays open and untested, with no claim in either
direction. It would have been easy to combine round 6's stall with this round's
dead KIQ into "MAP_QUEUES is gated everywhere"; neither result supports that,
because a queue that never activates cannot refuse anything.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Round 5 closed the direct route (unprivileged queues cannot write registers), so
the follow-up is the indirect one: use MAP_QUEUES from an unprivileged queue to
map a queue whose MQD sets priv_state=1, then write registers through it. That
would be a user->kernel chain requiring no memory-safety bug at all.
The test is inconclusive and is recorded that way. MAP_QUEUES stalls the queue
identically at priv_state=0 and priv_state=1, and identically again after seeding
the target MQD with the one the driver had just built. Because the privileged
queue stalls too, the stall is not a privilege effect -- MAP_QUEUES is an
HIQ/KIQ-pipe packet and is not serviced on an ordinary compute ring.
Worth stating because the failure mode is deceptive: a stall looks exactly like
the round-5 privilege fault, and without the priv_state=1 comparison this would
have been written up as "the gate covers MAP_QUEUES too". The probe's verdict
text is corrected to say a stall alone proves nothing.
The chain stays open. Testing it needs HIQ submission with a user-owned ring,
which tinygrad's AM does not expose (setup_ring(kiq_xcc=0) indexes past its
allocated MQD slots) -- a driver-plumbing blocker, not a firmware one.
|
|
|
PM4 is submitted by unprivileged user queues and WRITE_DATA(dst_sel=register)
names a memory-mapped register, so an ungated path would be the user->kernel
primitive none of the DMCUB findings can be.
Tested as a 2x2 on silicon, because either factor alone is uninterpretable:
dst=memory dst=register
priv_state=0 wrote refused, queue then faults
priv_state=1 wrote wrote, queue alive
The memory column proves the packet encoding, ring, doorbell and submission path
are correct -- without it, "the register did not change" is equally consistent
with a malformed packet, which is exactly what made the first SDMA RB_PRIV=0 run
inconclusive. The priv_state=1 row rules out the other explanation, that
WRITE_DATA->register is simply unsupported on MEC.
Privilege was changed by live-flipping CP_HQD_PQ_CONTROL (0x8509 -> 0xc0008509)
on an already-running queue, so that bit is the only difference between the two
runs -- the same isolation technique used for SDMA's RB_PRIV.
Verdict: the boundary is real and enforced on gfx11. Across both user-submittable
engines the pattern is identical -- memory confined by the VM, registers gated by
a per-queue privilege bit, and the gate holds. Also fixes the probe's verdict
text, which printed the unprivileged conclusion for a privileged run.
|