fix(libc): register guest heap blocks without GPU access
AnyPS5's libc heap registered every block with GPU access, so every address-based build imported or mirrored each malloc block the title had made. The console's libc.prx maps its heap with protection 3 (CPU read and write, no GPU bits), so the GPU never sees it there either. Heap blocks are now registered without GPU access; reallocating keeps the block's access. The AvPlayer fallback for a title that passes no texture allocator stands in for that allocator, which hands out memory the GPU reads, so it allocates through a new GuestHeapAlignForGpu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d31b57a4ca
commit
aa013f59ac
|
|
@ -741,11 +741,38 @@ void RunBdaResourceTests(const Context& context, const BdaTestAccess& access) {
|
|||
tail.Upload(true);
|
||||
reject([&] { tail.Descriptor(address + 58, 4, adjustment); }, "exceeds its GPU owner");
|
||||
}
|
||||
{
|
||||
void* plain = GuestHeap::GuestHeapAllocate_nid_postfix(64);
|
||||
void* gpu = GuestHeap::GuestHeapAlignForGpu_nid_postfix(16, 64);
|
||||
const auto lookup = [](const void* pointer) {
|
||||
GuestAllocations::Mutation mutation;
|
||||
return mutation.Find(pointer);
|
||||
};
|
||||
Require(!lookup(plain).gpu && lookup(gpu).gpu, "a guest heap block's GPU access does not follow how it was allocated");
|
||||
gpu = GuestHeap::GuestHeapReallocate_nid_postfix(gpu, 128);
|
||||
plain = GuestHeap::GuestHeapRealign_nid_postfix(plain, 128, 64);
|
||||
Require(!lookup(plain).gpu && lookup(gpu).gpu, "a reallocated guest heap block changed its GPU access");
|
||||
{
|
||||
GuestBufferMemory leased(context);
|
||||
leased.AcquireRegistered();
|
||||
leased.Upload(true);
|
||||
const auto ranges = leased.AddressRanges();
|
||||
const auto listed = [&](const void* pointer) {
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(pointer);
|
||||
return std::any_of(ranges.begin(), ranges.end(), [&](const auto& range) { return range.begin <= address && address < range.end; });
|
||||
};
|
||||
Require(!listed(plain), "a guest heap block without GPU access is in an address-based build");
|
||||
Require(listed(gpu), "a guest heap block with GPU access is missing from an address-based build");
|
||||
leased.WriteBack();
|
||||
}
|
||||
GuestHeap::GuestHeapFree_nid_postfix(plain);
|
||||
GuestHeap::GuestHeapFree_nid_postfix(gpu);
|
||||
}
|
||||
{
|
||||
// The cached address space: a second build in an unchanged registry takes the first one's
|
||||
// space, and a guest free of a range pinned only by the cache goes through the pin waiter's
|
||||
// drop (no GPU work to wait for) and empties the registry of it.
|
||||
void* block = GuestHeap::GuestHeapAllocate_nid_postfix(64);
|
||||
void* block = GuestHeap::GuestHeapAlignForGpu_nid_postfix(16, 64);
|
||||
const auto blockAddress = reinterpret_cast<std::uintptr_t>(block);
|
||||
std::memset(block, 0x5a, 64);
|
||||
const auto registered = [&] {
|
||||
|
|
|
|||
|
|
@ -450,8 +450,8 @@ std::array<std::uint32_t, 7> memoryCopy(const void* destination, const void* sou
|
|||
void testCopyIntoHostMemory() {
|
||||
constexpr std::size_t words = 32768;
|
||||
constexpr auto bytes = static_cast<std::uint32_t>(words * 4);
|
||||
auto* produced = static_cast<std::uint32_t*>(GuestHeap::GuestHeapAlign_nid_postfix(65536, bytes));
|
||||
auto* source = static_cast<std::uint32_t*>(GuestHeap::GuestHeapAlign_nid_postfix(65536, bytes));
|
||||
auto* produced = static_cast<std::uint32_t*>(GuestHeap::GuestHeapAlignForGpu_nid_postfix(65536, bytes));
|
||||
auto* source = static_cast<std::uint32_t*>(GuestHeap::GuestHeapAlignForGpu_nid_postfix(65536, bytes));
|
||||
std::vector<std::uint32_t> destination(words);
|
||||
for (const bool label : {false, true}) {
|
||||
for (std::size_t i = 0; i < words; ++i) {
|
||||
|
|
|
|||
|
|
@ -29,13 +29,17 @@ void APS5_VABI GuestDeallocate_nid_no_patch(void*, void* memory) {
|
|||
GuestHeap::GuestHeapFree_nid_postfix(memory);
|
||||
}
|
||||
|
||||
void* APS5_VABI GuestAllocateTexture_nid_no_patch(void*, std::uint32_t alignment, std::uint32_t size) {
|
||||
return GuestHeap::GuestHeapAlignForGpu_nid_postfix(std::max<std::uint32_t>(alignment, 16), size);
|
||||
}
|
||||
|
||||
AvPlayerMemAllocator WithGuestHeapFallback(AvPlayerMemAllocator memory) {
|
||||
if (!memory.allocate || !memory.deallocate) {
|
||||
memory.allocate = GuestAllocate_nid_no_patch;
|
||||
memory.deallocate = GuestDeallocate_nid_no_patch;
|
||||
}
|
||||
if (!memory.allocate_texture || !memory.deallocate_texture) {
|
||||
memory.allocate_texture = GuestAllocate_nid_no_patch;
|
||||
memory.allocate_texture = GuestAllocateTexture_nid_no_patch;
|
||||
memory.deallocate_texture = GuestDeallocate_nid_no_patch;
|
||||
}
|
||||
return memory;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ void GuestHeapFree_nid_postfix(void* pointer);
|
|||
void* GuestHeapReallocate_nid_postfix(void* pointer, std::size_t bytes);
|
||||
void* GuestHeapAlign_nid_postfix(std::size_t alignment, std::size_t bytes);
|
||||
void* GuestHeapRealign_nid_postfix(void* pointer, std::size_t bytes, std::size_t alignment);
|
||||
void* GuestHeapAlignForGpu_nid_postfix(std::size_t alignment, std::size_t bytes);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ void rawFree(void* raw, std::size_t blockBytes) {
|
|||
else std::free(raw);
|
||||
}
|
||||
|
||||
void* allocate(GuestAllocations::Mutation& mutation, std::size_t alignment, std::size_t bytes) {
|
||||
void* allocate(GuestAllocations::Mutation& mutation, std::size_t alignment, std::size_t bytes, bool gpu) {
|
||||
if (alignment == 0 || (alignment & (alignment - 1)) != 0) throw std::invalid_argument("invalid guest heap alignment");
|
||||
alignment = std::max(alignment, MinimumAlignment);
|
||||
const std::size_t padding = alignment > RawAlignment ? alignment : 0;
|
||||
|
|
@ -205,7 +205,7 @@ void* allocate(GuestAllocations::Mutation& mutation, std::size_t alignment, std:
|
|||
reinterpret_cast<void**>(pointer)[-2] = raw;
|
||||
reinterpret_cast<std::size_t*>(pointer)[-1] = blockBytes;
|
||||
try {
|
||||
mutation.Add(pointer, bytes, true, true, true);
|
||||
mutation.Add(pointer, bytes, true, true, gpu);
|
||||
} catch (...) {
|
||||
rawFree(raw, blockBytes);
|
||||
throw;
|
||||
|
|
@ -222,7 +222,7 @@ void free(GuestAllocations::Mutation& mutation, void* pointer) {
|
|||
|
||||
void* GuestHeapAllocate_nid_postfix(std::size_t bytes) {
|
||||
GuestAllocations::Mutation mutation;
|
||||
return allocate(mutation, MinimumAlignment, bytes);
|
||||
return allocate(mutation, MinimumAlignment, bytes, false);
|
||||
}
|
||||
|
||||
void GuestHeapFree_nid_postfix(void* pointer) {
|
||||
|
|
@ -242,7 +242,7 @@ void* GuestHeapReallocate_nid_postfix(void* pointer, std::size_t bytes) {
|
|||
free(mutation, pointer);
|
||||
return nullptr;
|
||||
}
|
||||
void* result = allocate(mutation, MinimumAlignment, bytes);
|
||||
void* result = allocate(mutation, MinimumAlignment, bytes, range.gpu);
|
||||
std::memcpy(result, pointer, std::min(bytes, range.bytes));
|
||||
free(mutation, pointer);
|
||||
return result;
|
||||
|
|
@ -257,7 +257,7 @@ void* GuestHeapRealign_nid_postfix(void* pointer, std::size_t bytes, std::size_t
|
|||
free(mutation, pointer);
|
||||
return nullptr;
|
||||
}
|
||||
void* result = allocate(mutation, alignment, bytes);
|
||||
void* result = allocate(mutation, alignment, bytes, range.gpu);
|
||||
std::memcpy(result, pointer, std::min(bytes, range.bytes));
|
||||
free(mutation, pointer);
|
||||
return result;
|
||||
|
|
@ -265,7 +265,12 @@ void* GuestHeapRealign_nid_postfix(void* pointer, std::size_t bytes, std::size_t
|
|||
|
||||
void* GuestHeapAlign_nid_postfix(std::size_t alignment, std::size_t bytes) {
|
||||
GuestAllocations::Mutation mutation;
|
||||
return allocate(mutation, alignment, bytes);
|
||||
return allocate(mutation, alignment, bytes, false);
|
||||
}
|
||||
|
||||
void* GuestHeapAlignForGpu_nid_postfix(std::size_t alignment, std::size_t bytes) {
|
||||
GuestAllocations::Mutation mutation;
|
||||
return allocate(mutation, alignment, bytes, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue