Merge pull request #4395 from oneandonlydean/up4/carry-1810
fix(agc): cache Linux describePages results
This commit is contained in:
commit
3d8ffeb271
|
|
@ -423,6 +423,17 @@ struct PageStates {
|
|||
arena.forget(address, bytes);
|
||||
image.forget(address, bytes);
|
||||
}
|
||||
|
||||
void record(std::uintptr_t base, std::uintptr_t regionEnd, bool readable, bool writable, std::uint64_t generation) {
|
||||
for (PageSpan* span : {&arena, &image}) {
|
||||
if (!readable || span->size == 0 || regionEnd <= span->base || base >= span->base + span->size) continue;
|
||||
const std::uint8_t value = PageReadable | (writable ? PageWritable : 0u);
|
||||
const auto first = std::max(base, span->base);
|
||||
const auto last = std::min(regionEnd, span->base + span->size);
|
||||
for (auto at = first; at < last; at += PageBytes) span->store(at, value);
|
||||
if (GuestAllocations::GuestAllocationsGeneration_nid_postfix() != generation) span->forget(first, static_cast<std::size_t>(last - first));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PageStates& Pages() {
|
||||
|
|
@ -533,18 +544,16 @@ bool describePages(std::uintptr_t address, std::size_t bytes, Emit&& emit) {
|
|||
const bool committed = memory.State == MEM_COMMIT && (memory.Protect & (PAGE_GUARD | PAGE_NOACCESS)) == 0;
|
||||
const bool readable = committed && readableProtection(protection);
|
||||
const bool writable = readable && writableProtection(protection);
|
||||
for (PageSpan* span : {&pages.arena, &pages.image}) {
|
||||
if (!readable || span->size == 0 || regionEnd <= span->base || base >= span->base + span->size) continue;
|
||||
const std::uint8_t value = PageReadable | (writable ? PageWritable : 0u);
|
||||
const auto first = std::max(base, span->base);
|
||||
const auto last = std::min(regionEnd, span->base + span->size);
|
||||
for (auto at = first; at < last; at += PageBytes) span->store(at, value);
|
||||
if (GuestAllocations::GuestAllocationsGeneration_nid_postfix() != generation) span->forget(first, static_cast<std::size_t>(last - first));
|
||||
}
|
||||
pages.record(base, regionEnd, readable, writable, generation);
|
||||
const auto next = std::min(end, regionEnd);
|
||||
if (!emit(PageRun{cursor, next, readable, writable})) return true;
|
||||
cursor = next;
|
||||
#else
|
||||
const auto generation = GuestAllocations::GuestAllocationsGeneration_nid_postfix();
|
||||
const auto recordRun = [&](std::uintptr_t next, bool readable, bool writable) {
|
||||
constexpr auto mask = static_cast<std::uintptr_t>(PageBytes - 1);
|
||||
pages.record(cursor & ~mask, (next + mask) & ~mask, readable, writable, generation);
|
||||
};
|
||||
if (const int fd = HostMapping::QueryFd(); fd >= 0) {
|
||||
procmap_query query{};
|
||||
query.size = sizeof(query);
|
||||
|
|
@ -559,8 +568,10 @@ bool describePages(std::uintptr_t address, std::size_t bytes, Emit&& emit) {
|
|||
continue;
|
||||
}
|
||||
const bool readable = (query.vma_flags & PROCMAP_QUERY_VMA_READABLE) != 0;
|
||||
const bool writable = readable && (query.vma_flags & PROCMAP_QUERY_VMA_WRITABLE) != 0;
|
||||
const auto next = std::min<std::uintptr_t>(end, query.vma_end);
|
||||
if (!emit(PageRun{cursor, next, readable, readable && (query.vma_flags & PROCMAP_QUERY_VMA_WRITABLE) != 0})) return true;
|
||||
recordRun(next, readable, writable);
|
||||
if (!emit(PageRun{cursor, next, readable, writable})) return true;
|
||||
cursor = next;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -589,8 +600,11 @@ bool describePages(std::uintptr_t address, std::size_t bytes, Emit&& emit) {
|
|||
found = true;
|
||||
break;
|
||||
}
|
||||
const bool readable = permissions[0] == 'r';
|
||||
const bool writable = readable && permissions[1] == 'w';
|
||||
const auto next = std::min(end, last);
|
||||
if (!emit(PageRun{cursor, next, permissions[0] == 'r', permissions[0] == 'r' && permissions[1] == 'w'})) return true;
|
||||
recordRun(next, readable, writable);
|
||||
if (!emit(PageRun{cursor, next, readable, writable})) return true;
|
||||
cursor = next;
|
||||
found = true;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "BdaTests.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "prx/libc/include/GuestArena.hpp"
|
||||
#include "prx/libc/include/GuestHeap.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp"
|
||||
|
|
@ -187,5 +188,36 @@ void RunUnmappedGapTests() {
|
|||
Require(!GuestMemory::Accessible(reinterpret_cast<const void*>(std::uintptr_t{0x18}), 4), "a near-null address counts as accessible");
|
||||
munmap(block, page);
|
||||
munmap(block + 2 * page, page);
|
||||
if (!GuestArena::GuestArenaAvailable_nid_postfix()) return;
|
||||
auto* guest = static_cast<std::byte*>(GuestArena::GuestArenaAllocate_nid_postfix(2 * page, page));
|
||||
Require(mmap(guest, 2 * page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == guest, "cannot map the arena page test pages");
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(guest, 2 * page, true, true, true);
|
||||
}
|
||||
Require(GuestMemory::Accessible(guest, page, true), "a mapped arena page is not writable");
|
||||
Require(mprotect(guest, page, PROT_NONE) == 0, "cannot revoke the arena test page behind the registry");
|
||||
Require(GuestMemory::Accessible(guest, page, true), "a checked arena page was queried again instead of read from the page table");
|
||||
Require(mprotect(guest, page, PROT_READ | PROT_WRITE) == 0, "cannot restore the arena test page behind the registry");
|
||||
Require(mprotect(guest + page, page, PROT_READ) == 0, "cannot protect the arena test's second page");
|
||||
Require(!GuestMemory::Accessible(guest + page, page, true), "a check stored arena pages outside its range");
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Protect(guest + page, page, true, true, true, [&] { Require(mprotect(guest + page, page, PROT_READ | PROT_WRITE) == 0, "cannot restore the arena test's second page"); });
|
||||
}
|
||||
Require(GuestMemory::Accessible(guest, 2 * page, true), "mapped arena pages are not writable");
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Protect(guest, page, true, false, true, [&] { Require(mprotect(guest, page, PROT_READ) == 0, "cannot protect the arena test page"); });
|
||||
}
|
||||
Require(!GuestMemory::Accessible(guest, page, true) && GuestMemory::Accessible(guest, page) && GuestMemory::Accessible(guest + page, page, true), "an arena page protected through the registry kept its old access");
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
const auto release = [](const void* pointer, std::size_t bytes, const void*, bool) { Require(munmap(const_cast<void*>(pointer), bytes) == 0, "cannot unmap an arena test page"); };
|
||||
mutation.Unmap(guest, page, release);
|
||||
mutation.Unmap(guest + page, page, release);
|
||||
}
|
||||
Require(!GuestMemory::Accessible(guest, page) && !GuestMemory::Accessible(guest + page, page), "unmapped arena pages are still accessible");
|
||||
GuestArena::GuestArenaRelease_nid_postfix(guest, 2 * page);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue