fix(agc): cache Linux describePages results

This commit is contained in:
Swastik-51 2026-10-09 01:27:29 +05:30 committed by Dean Galvin
parent 2979ae37a3
commit 9f06176334
1 changed files with 22 additions and 10 deletions

View File

@ -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,12 @@ 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();
if (const int fd = HostMapping::QueryFd(); fd >= 0) {
procmap_query query{};
query.size = sizeof(query);
@ -558,9 +563,13 @@ bool describePages(std::uintptr_t address, std::size_t bytes, Emit&& emit) {
cursor = gapEnd;
continue;
}
const auto base = static_cast<std::uintptr_t>(query.vma_start);
const auto regionEnd = static_cast<std::uintptr_t>(query.vma_end);
const bool readable = (query.vma_flags & PROCMAP_QUERY_VMA_READABLE) != 0;
const bool writable = readable && (query.vma_flags & PROCMAP_QUERY_VMA_WRITABLE) != 0;
pages.record(base, regionEnd, readable, writable, generation);
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;
if (!emit(PageRun{cursor, next, readable, writable})) return true;
cursor = next;
continue;
}
@ -589,8 +598,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';
pages.record(first, last, readable, writable, generation);
const auto next = std::min(end, last);
if (!emit(PageRun{cursor, next, permissions[0] == 'r', permissions[0] == 'r' && permissions[1] == 'w'})) return true;
if (!emit(PageRun{cursor, next, readable, writable})) return true;
cursor = next;
found = true;
break;