D460 - Mapping direct memory commits into an existing reservation, it does not reserve again

measured - 2026-09-01 (user-directed /loop: crack the refers, immediately after D459)

PPSA02664 faulted writing to 0x0 at image+0xafcc08. The return column D459 added named the cause in one run: sceKernelMapDirectMemory answered 0x7fff0004 - GuestError::NoMemory - while sceKernelReserveVirtualRange, sceKernelVirtualQuery and sceKernelAllocateMainDirectMemory all answered 0x0 (OK). Three of the four memory calls succeeded and the map failed. This replaced the previous turn's guess (a wrong tlsf pool size, or an address-space mismatch), which the returns disproved outright.

The cause is reserve-then-map treated as reserve-twice. A guest carves a virtual range with sceKernelReserveVirtualRange and then places physical memory inside it with sceKernelMapDirectMemory, at the address it was handed. map_named_direct_memory called AddressSpace::reserve unconditionally, which validates against existing regions and returns MemError::Conflict for a range that overlaps one - and the range was the reservation the guest had just made. The map answered NoMemory, the guest read that as out-of-memory, kept the null its allocator returned, and wrote through it two instructions later on the branch D458 decoded.

The fix. AddressSpace::owns(base, len) - the containment test protect already performed inline, now named and shared - reports whether a range lies wholly within a region this space reserved. map_named_direct_memory consults it: a range the guest pre-reserved is committed into with protect (on orbistoun's identity-mapped model the reservation already backs the pages, so the map is a re-protect plus the physical-alias bookkeeping), and only a range it did not pre-reserve is a fresh mapping that still reserves. This is the true console semantics - reserve carves address space, map places physical memory within it - not a workaround.

Verified by two observations, not one (the D224/D226/D227 rule). The wall moved image+0xafcc08 -> image+0xb14be3, and the run went from 234 calls / 26 distinct imports to 1544 calls / 39 distinct imports (+1310, +13), verdict FURTHER. The second number is what makes it a fix rather than a wall shoved sideways: a program cannot make thirteen hundred more library calls without a working heap, so the allocator now initialises and the guest runs on. sceKernelMapDirectMemory answering 0x0 where it answered 0x7fff0004 is the same fact read the other way, from the very column that found it. The new wall, image+0xb14be3, is _Getpctype returning a placeholder the guest dereferences - already named by D459 and the next target. Provenance-clean: no guest code read; owns is a pure containment test with its own unit test.