fix(agc): address-based builds map only memory mapped for the GPU
The registry records whether a range was mapped or protected with GPU access (0x10/0x20), and an address-based build leaves out ranges without it, as the console's GPU page tables do. The main image is registered without GPU access; the title's own mprotect with GPU bits adds it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3d1a7d90c7
commit
c11a9cb59f
|
|
@ -1810,7 +1810,7 @@ void GuestBufferMemory::AcquireRegistered() {
|
|||
std::vector<AddressCopy> copies;
|
||||
std::vector<std::uint64_t> imported;
|
||||
for (const auto& range : lease) {
|
||||
if (!range->readable) continue;
|
||||
if (!range->readable || !range->gpu) continue;
|
||||
validate(range->address, range->bytes);
|
||||
Region region{range->address, range->address + range->bytes, range->writable, {}, nullptr};
|
||||
const HostImport* entry = nullptr;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ void importCrossingTests(const Context& context, const BdaTestAccess& access) {
|
|||
const auto registry = [&](bool add) {
|
||||
auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix();
|
||||
for (auto* range : {guest, guest + half}) {
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, range, half, true, false);
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, range, half, true, false, true);
|
||||
else GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, range);
|
||||
}
|
||||
GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation);
|
||||
|
|
@ -108,7 +108,7 @@ void importedHeapMirrorTests(const Context& context, const BdaTestAccess& access
|
|||
importing.hostImportAlignment = bytes;
|
||||
const auto registry = [&](bool add) {
|
||||
auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix();
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, block, bytes, true, false);
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, block, bytes, true, false, true);
|
||||
else GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, block);
|
||||
GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation);
|
||||
};
|
||||
|
|
@ -163,7 +163,7 @@ void importedFreshTests(const Context& context) {
|
|||
importing.hostImportAlignment = blockBytes;
|
||||
const auto registry = [&](bool add) {
|
||||
auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix();
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, reinterpret_cast<void*>(base), blockBytes, true, true);
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, reinterpret_cast<void*>(base), blockBytes, true, true, true);
|
||||
else GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, reinterpret_cast<void*>(base));
|
||||
GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation);
|
||||
};
|
||||
|
|
@ -279,7 +279,7 @@ void heapMirrorTests(const Context& context, const BdaTestAccess& access) {
|
|||
const auto address = reinterpret_cast<std::uintptr_t>(block);
|
||||
const auto registry = [&](bool add, bool writable) {
|
||||
auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix();
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, block, bytes, true, writable);
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, block, bytes, true, writable, true);
|
||||
else GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, block);
|
||||
GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation);
|
||||
};
|
||||
|
|
@ -370,7 +370,7 @@ void heapMirrorTests(const Context& context, const BdaTestAccess& access) {
|
|||
const auto registerPair = [&](bool add) {
|
||||
auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix();
|
||||
for (auto* range : {first, second}) {
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, range, half, true, false);
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, range, half, true, false, true);
|
||||
else GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, range);
|
||||
}
|
||||
GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation);
|
||||
|
|
@ -423,7 +423,7 @@ void heapMirrorTests(const Context& context, const BdaTestAccess& access) {
|
|||
GuestAllocations::GuestAllocationsInvalidate_nid_postfix(page, 4096);
|
||||
const auto registerRange = [&](bool add) {
|
||||
auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix();
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, raw, size, true, true);
|
||||
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, raw, size, true, true, true);
|
||||
else GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, raw);
|
||||
GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation);
|
||||
};
|
||||
|
|
@ -483,7 +483,7 @@ void heapMirrorTests(const Context& context, const BdaTestAccess& access) {
|
|||
const auto change = [&](std::initializer_list<std::size_t> added, std::initializer_list<std::size_t> removed) {
|
||||
auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix();
|
||||
for (const auto index : removed) GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, heaps[index]);
|
||||
for (const auto index : added) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, heaps[index], sizes[index], true, false);
|
||||
for (const auto index : added) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, heaps[index], sizes[index], true, false, true);
|
||||
GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation);
|
||||
};
|
||||
const auto mirrored = [&](std::size_t index) {
|
||||
|
|
@ -541,6 +541,34 @@ void heapMirrorTests(const Context& context, const BdaTestAccess& access) {
|
|||
|
||||
}
|
||||
|
||||
void gpuMappingTests(const Context& context) {
|
||||
constexpr std::size_t bytes = 65536;
|
||||
auto* cpu = static_cast<std::byte*>(::operator new(bytes, std::align_val_t{bytes}));
|
||||
auto* gpu = static_cast<std::byte*>(::operator new(bytes, std::align_val_t{bytes}));
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(cpu, bytes, true, true, false);
|
||||
mutation.Add(gpu, bytes, true, true, true);
|
||||
}
|
||||
{
|
||||
GuestBufferMemory leased(context);
|
||||
leased.AcquireRegistered();
|
||||
leased.Upload(true);
|
||||
const auto ranges = leased.AddressRanges();
|
||||
const auto has = [&](const std::byte* block) { return std::any_of(ranges.begin(), ranges.end(), [&](const auto& range) { return range.begin == reinterpret_cast<std::uintptr_t>(block); }); };
|
||||
Require(has(gpu), "a GPU-mapped range is missing from the BDA table");
|
||||
Require(!has(cpu), "a range mapped without GPU access is in the BDA table");
|
||||
leased.WriteBack();
|
||||
}
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Remove(cpu);
|
||||
mutation.Remove(gpu);
|
||||
}
|
||||
::operator delete(cpu, std::align_val_t{bytes});
|
||||
::operator delete(gpu, std::align_val_t{bytes});
|
||||
}
|
||||
|
||||
void RunBdaResourceTests(const Context& context, const BdaTestAccess& access) {
|
||||
alignas(64) std::array<std::uint32_t, 16> guest{};
|
||||
guest[0] = 123;
|
||||
|
|
@ -694,6 +722,7 @@ void RunBdaResourceTests(const Context& context, const BdaTestAccess& access) {
|
|||
importedHeapMirrorTests(context, access);
|
||||
importWatchTests();
|
||||
importedFreshTests(context);
|
||||
gpuMappingTests(context);
|
||||
Require(AddressCopyOverflow({{0x1000, 0x3000, 0x2000, "uncommitted pages"}}, 0x2000).empty(), "copies within the limit were refused");
|
||||
const auto copies = AddressCopyOverflow({{0x1000, 0x2000, 0x1000, "not mirrored"}, {0x10000, 0x30000, 0x18000, "uncommitted pages"}}, 0x2000);
|
||||
Require(!copies.empty() && copies.find("0x10000+0x20000 (0.1 MiB committed, uncommitted pages)") < copies.find("0x1000+0x1000"), "the copy limit does not name the largest copy first");
|
||||
|
|
|
|||
|
|
@ -177,8 +177,8 @@ int main() {
|
|||
}
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(SurfaceStorage.data(), SurfaceStorage.size(), true, true);
|
||||
mutation.Add(Cmask.data(), Cmask.size(), true, true);
|
||||
mutation.Add(SurfaceStorage.data(), SurfaceStorage.size(), true, true, true);
|
||||
mutation.Add(Cmask.data(), Cmask.size(), true, true, true);
|
||||
}
|
||||
run(*device, ColorTileMode::Linear, "linear");
|
||||
run(*device, ColorTileMode::RenderTarget, "SW_64KB_R_X");
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ void RunGuestLeaseWaitTests() {
|
|||
const auto address = reinterpret_cast<std::uintptr_t>(memory.data());
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(memory.data(), 64, true, true);
|
||||
mutation.Add(memory.data() + 64, 64, true, true);
|
||||
mutation.Add(memory.data(), 64, true, true, true);
|
||||
mutation.Add(memory.data() + 64, 64, true, true, true);
|
||||
}
|
||||
auto lease = GuestAllocations::GuestAllocationsAcquire_nid_postfix();
|
||||
std::erase_if(lease, [&](const auto& range) { return range->address != address; });
|
||||
|
|
@ -83,7 +83,7 @@ void RunGuestAllocationTests() {
|
|||
reject([&] { GuestHeap::GuestHeapReallocate_nid_postfix(pointer, 64); });
|
||||
GuestAllocations::Mutation mutation;
|
||||
bool applied = false;
|
||||
reject([&] { mutation.Protect(pointer, 32, true, false, [&] { applied = true; }); });
|
||||
reject([&] { mutation.Protect(pointer, 32, true, false, true, [&] { applied = true; }); });
|
||||
Require(!applied, "pinned guest protection changed");
|
||||
}
|
||||
pointer = GuestHeap::GuestHeapReallocate_nid_postfix(pointer, 64);
|
||||
|
|
@ -102,9 +102,9 @@ void RunGuestAllocationTests() {
|
|||
std::array<std::byte, 128> mapping{};
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(mapping.data(), mapping.size(), true, true);
|
||||
mutation.Add(mapping.data(), mapping.size(), true, true, true);
|
||||
reject([&] { mutation.RequireAvailable(mapping.data() + 32, 16); });
|
||||
mutation.Protect(mapping.data() + 32, 32, true, false, [] {});
|
||||
mutation.Protect(mapping.data() + 32, 32, true, false, true, [] {});
|
||||
}
|
||||
{
|
||||
const auto lease = GuestAllocations::GuestAllocationsAcquire_nid_postfix();
|
||||
|
|
@ -120,7 +120,7 @@ void RunGuestAllocationTests() {
|
|||
applied = true;
|
||||
});
|
||||
Require(applied, "partial unmap callback was not called");
|
||||
reject([&] { mutation.Protect(mapping.data(), mapping.size(), true, true, [] {}); });
|
||||
reject([&] { mutation.Protect(mapping.data(), mapping.size(), true, true, true, [] {}); });
|
||||
mutation.Unmap(mapping.data(), 32, [&](const void*, std::size_t, const void* allocation, bool last) {
|
||||
Require(allocation == mapping.data() && !last, "first fragment released remaining mapping");
|
||||
});
|
||||
|
|
@ -144,10 +144,11 @@ void RunGuestAllocationTests() {
|
|||
imageRangeCount = lease.size();
|
||||
const auto found = std::find_if(lease.begin(), lease.end(), [&](const auto& range) { return imageAddress >= range->address && imageAddress - range->address < range->bytes; });
|
||||
Require(found != lease.end() && (*found)->writable && !(*found)->releasable, "main image registration is missing or releasable");
|
||||
Require(std::none_of(lease.begin(), lease.end(), [](const auto& range) { return !range->releasable && range->gpu; }), "main image registered as GPU-mapped");
|
||||
allocationAddress = (*found)->allocationAddress;
|
||||
GuestAllocations::Mutation mutation;
|
||||
bool applied = false;
|
||||
reject([&] { mutation.Protect(&imageProbe, 1, true, false, [&] { applied = true; }); });
|
||||
reject([&] { mutation.Protect(&imageProbe, 1, true, false, true, [&] { applied = true; }); });
|
||||
Require(!applied, "pinned image protection changed");
|
||||
}
|
||||
{
|
||||
|
|
@ -157,12 +158,12 @@ void RunGuestAllocationTests() {
|
|||
bool applied = false;
|
||||
reject([&] { mutation.Unmap(&imageProbe, 1, [&](const void*, std::size_t, const void*, bool) { applied = true; }); });
|
||||
Require(!applied, "image memory was unmapped");
|
||||
reject([&] { mutation.Protect(&imageProbe, 1, true, false, [] { throw std::runtime_error("host protection failure"); }); });
|
||||
reject([&] { mutation.Protect(&imageProbe, 1, true, false, true, [] { throw std::runtime_error("host protection failure"); }); });
|
||||
}
|
||||
Require(GuestAllocations::GuestAllocationsAcquire_nid_postfix().size() == imageRangeCount, "failed image protection changed registry ranges");
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Protect(&imageProbe, 1, true, true, [] {});
|
||||
mutation.Protect(&imageProbe, 1, true, true, true, [] {});
|
||||
bool applied = false;
|
||||
reject([&] { mutation.Unmap(&imageProbe, 1, [&](const void*, std::size_t, const void*, bool) { applied = true; }); });
|
||||
Require(!applied, "split image memory became releasable");
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ int main() {
|
|||
auto* record = static_cast<std::uint32_t*>(::operator new(recordBlockBytes, std::align_val_t{65536}));
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(record, recordBlockBytes, true, true);
|
||||
mutation.Add(record, recordBlockBytes, true, true, true);
|
||||
}
|
||||
const auto drawIndirect = [&](std::uint32_t count, std::uint32_t instances, std::uint32_t first) {
|
||||
const std::array<std::uint32_t, 5> words{count, instances, first, 0u, 0u};
|
||||
|
|
|
|||
|
|
@ -742,7 +742,7 @@ void storeRunTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
const auto* import = HostImportFor(context, address, bytes);
|
||||
if (import == nullptr) {
|
||||
|
|
@ -816,7 +816,7 @@ void remappedImportTests(const Device& device) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
if (HostImportFor(context, address, bytes) == nullptr) {
|
||||
std::cout << "host import of the remap test block refused: remapped imports not tested\n";
|
||||
|
|
@ -827,7 +827,7 @@ void remappedImportTests(const Device& device) {
|
|||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Remove(block);
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
Require(HostImportFor(context, address, bytes) != nullptr, "the remapped range was not imported again");
|
||||
const auto second = HostImportSerial(context, address, bytes, true);
|
||||
|
|
@ -861,7 +861,7 @@ void movedMetadataTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -954,7 +954,7 @@ void viewPastLastMipTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -1038,7 +1038,7 @@ void resourceReadTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
if (HostImportFor(context, address, bytes) == nullptr) {
|
||||
std::cout << "host import of the test block refused: resource read notes not tested\n";
|
||||
|
|
@ -1146,7 +1146,7 @@ void misalignedRegionTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -1234,7 +1234,7 @@ void misalignedSnapshotTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -1309,7 +1309,7 @@ void drawSnapshotReuseTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -1461,7 +1461,7 @@ void drawInputReuseTests(const Device& device, Recorder& recorder) {
|
|||
alignas(64) static std::byte other[64];
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(other, sizeof(other), true, true);
|
||||
mutation.Add(other, sizeof(other), true, true, true);
|
||||
}
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
|
|
@ -1506,7 +1506,7 @@ void drawInputInPlaceTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -1578,7 +1578,7 @@ void unitShadowTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -1732,7 +1732,7 @@ void unitShadowTests(const Device& device, Recorder& recorder) {
|
|||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Remove(block);
|
||||
mutation.Add(block, static_cast<std::size_t>(5 * unit), true, true);
|
||||
mutation.Add(block, static_cast<std::size_t>(5 * unit), true, true, true);
|
||||
}
|
||||
Require(HostImportFor(context, address, bytes) == nullptr, "a shrunk registration still imports the old range");
|
||||
Require(!AnyShadowedOverlaps(address, bytes), "the retired import's shadow survived");
|
||||
|
|
@ -1775,7 +1775,7 @@ void storageRefreshTests(const Device& device, Recorder& recorder, bool watched)
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -1962,7 +1962,7 @@ void hostImportUnmapTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
const HostImport* imported = nullptr;
|
||||
{
|
||||
|
|
@ -2036,7 +2036,7 @@ void importWatchTests(const Device& device) {
|
|||
};
|
||||
const auto registerRange = [](void* block, std::size_t bytes) {
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
};
|
||||
const auto unregisterRange = [](void* block) {
|
||||
GuestAllocations::Mutation mutation;
|
||||
|
|
@ -2140,7 +2140,7 @@ void staleGenerationTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -2282,7 +2282,7 @@ void writeBackPaddingTests(const Device& device, Recorder& recorder, bool watche
|
|||
const auto address = blockAddress + test.offset;
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -2385,7 +2385,7 @@ void unchangedCpuStampTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = blockAddress + offset;
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -2509,7 +2509,7 @@ void importWindowTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -2897,7 +2897,7 @@ void pendingKeyStoreTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -2964,7 +2964,7 @@ void sampleDumpTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -3036,7 +3036,7 @@ void metadataPassTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -3563,7 +3563,7 @@ void keysFillTests(const Device& device, Recorder& recorder) {
|
|||
const auto keysAddress = address + surfaceBytes;
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
@ -3673,7 +3673,7 @@ void denormalClearTests(const Device& device, Recorder& recorder) {
|
|||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true);
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "BDA span reads: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ public:
|
|||
#endif
|
||||
Require(block != nullptr, "bvh64 intersect ray: cannot allocate the guest block");
|
||||
std::memset(block, 0, BlockBytes);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public:
|
|||
#endif
|
||||
Require(block != nullptr, "constant store: cannot allocate the guest block");
|
||||
Clear();
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ public:
|
|||
#endif
|
||||
Require(block != nullptr, "DCC keys first write: cannot allocate the guest block");
|
||||
Require(!watched || AgcDriver::GuestMemory::Watched(AddressOf(block), BlockBytes), "DCC keys first write: the watched guest block is not write-watched");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ public:
|
|||
std::copy(instance.begin(), instance.end(), BufferTable.begin() + 4);
|
||||
records = static_cast<std::uint32_t*>(::operator new(RecordBytes, std::align_val_t{65536}));
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(records, RecordBytes, true, true);
|
||||
mutation.Add(records, RecordBytes, true, true, true);
|
||||
}
|
||||
|
||||
std::vector<std::uint32_t> UserData(std::uint32_t baseVertex, std::uint32_t startInstance) const {
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ struct Block {
|
|||
Require(data != nullptr, "cannot allocate the color target");
|
||||
Require(!watched || AgcDriver::GuestMemory::Watched(Address(), bytes), "the color target is not write-watched");
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(data, bytes, true, true);
|
||||
mutation.Add(data, bytes, true, true, true);
|
||||
}
|
||||
~Block() {
|
||||
AgcDriver::Graphics::StorageTexture::FlushPending(Address(), bytes, nullptr, "test release");
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public:
|
|||
#endif
|
||||
Require(block != nullptr, "fill cover test: cannot allocate the guest block");
|
||||
std::memset(block, 0, BlockBytes);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "flat cache bits: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -482,7 +482,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "flat d16 loads: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "flat loads: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "flat loads x2 x3: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "flat loads x4: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ public:
|
|||
#endif
|
||||
Require(block != nullptr, "flat store: cannot allocate the guest block");
|
||||
Clear();
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global atomic csub: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global atomics: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global atomics: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -585,7 +585,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global float atomics: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global atomics: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global loads: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global loads x2 x3: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global loads x4: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global store addtid: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global vcc base: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public:
|
|||
#endif
|
||||
Require(block != nullptr, "host import teardown: cannot allocate the guest block");
|
||||
std::memset(block, 0, BlockBytes);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ int main() {
|
|||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestAllocations::Mutation().Add(Texels.data(), Bytes, true, true);
|
||||
GuestAllocations::Mutation().Add(Texels.data(), Bytes, true, true, true);
|
||||
constexpr Format r8{R8UInt, 1u, 1u};
|
||||
constexpr Format r16{R16UInt, 2u, 1u};
|
||||
constexpr Format rg8{Rg8UInt, 1u, 2u};
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "image converted unorm: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ int main() {
|
|||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestAllocations::Mutation().Add(Texels.data(), Bytes, true, true);
|
||||
GuestAllocations::Mutation().Add(Texels.data(), Bytes, true, true, true);
|
||||
constexpr Format r8{R8UInt, 1u, 1u};
|
||||
constexpr Format r16{R16UInt, 2u, 1u};
|
||||
constexpr Format rg8{Rg8UInt, 1u, 2u};
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "image sRGB load: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "image store line through plane: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "image store packed: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "image store sint: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "masked global store: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
~GuestBlock() { GuestAllocations::Mutation().Remove(block); }
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ struct Block {
|
|||
Require(data != nullptr, "cannot allocate the color target");
|
||||
Require(!watched || AgcDriver::GuestMemory::Watched(Address(), bytes), "the color target is not write-watched");
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(data, bytes, true, true);
|
||||
mutation.Add(data, bytes, true, true, true);
|
||||
}
|
||||
~Block() {
|
||||
AgcDriver::Graphics::StorageTexture::FlushPending(Address(), bytes, nullptr, "test release");
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ int main() {
|
|||
std::fill(texels, texels + BlockBytes / 4u, Untouched);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(texels, BlockBytes, true, true);
|
||||
mutation.Add(texels, BlockBytes, true, true, true);
|
||||
}
|
||||
const auto surface = AddressOf(texels);
|
||||
const auto chainBytes = GuestBytes(texels, 1u);
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ struct Block {
|
|||
Require(data != nullptr, "cannot allocate the color target");
|
||||
Require(!watched || AgcDriver::GuestMemory::Watched(Address(), bytes), "the color target is not write-watched");
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(data, bytes, true, true);
|
||||
mutation.Add(data, bytes, true, true, true);
|
||||
}
|
||||
~Block() {
|
||||
AgcDriver::Graphics::StorageTexture::FlushPending(Address(), bytes, nullptr, "test release");
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(GuestBytes, 2 * GuestBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "pixel interlock: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, GuestBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, GuestBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestCounters() {
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ struct Block {
|
|||
Require(data != nullptr, "cannot allocate the color target");
|
||||
Require(!watched || AgcDriver::GuestMemory::Watched(Address(), bytes), "the color target is not write-watched");
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(data, bytes, true, true);
|
||||
mutation.Add(data, bytes, true, true, true);
|
||||
}
|
||||
~Block() {
|
||||
AgcDriver::Graphics::StorageTexture::FlushPending(Address(), bytes, nullptr, "test release");
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ public:
|
|||
#endif
|
||||
Require(memory != nullptr, "cannot allocate the texture block");
|
||||
std::memset(memory, 0x5a, BlockBytes);
|
||||
GuestAllocations::Mutation().Add(memory, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(memory, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~Block() {
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ public:
|
|||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "scalar wide loads: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ struct Block {
|
|||
Require(data != nullptr, "cannot allocate the color target");
|
||||
Require(!watched || AgcDriver::GuestMemory::Watched(Address(), bytes), "the color target is not write-watched");
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(data, bytes, true, true);
|
||||
mutation.Add(data, bytes, true, true, true);
|
||||
}
|
||||
~Block() {
|
||||
AgcDriver::Graphics::StorageTexture::FlushPending(Address(), bytes, nullptr, "test release");
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ int main() {
|
|||
const auto blockBytes = static_cast<std::size_t>(SurfaceBytes + (MaxSurfaces - 1u) * Stride);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(texels, blockBytes, true, true);
|
||||
mutation.Add(texels, blockBytes, true, true, true);
|
||||
}
|
||||
const auto release = [&] {
|
||||
AgcDriver::Graphics::ClearCachedTextures(device->Device());
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ struct Block {
|
|||
Require(data != nullptr, "cannot allocate the color target");
|
||||
Require(!watched || AgcDriver::GuestMemory::Watched(Address(), bytes), "the color target is not write-watched");
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(data, bytes, true, true);
|
||||
mutation.Add(data, bytes, true, true, true);
|
||||
}
|
||||
~Block() {
|
||||
AgcDriver::Graphics::StorageTexture::FlushPending(Address(), bytes, nullptr, "test release");
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public:
|
|||
#endif
|
||||
Require(block != nullptr, "unimported label order: cannot allocate the guest block");
|
||||
std::memset(block, 0, BlockBytes);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ int main() {
|
|||
std::fill(texels, texels + SurfaceBytes / 4u, Untouched);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(texels, SurfaceBytes, true, true);
|
||||
mutation.Add(texels, SurfaceBytes, true, true, true);
|
||||
}
|
||||
Store(*device, texels, 3u, StorePastCode);
|
||||
Check(texels, false, "store through level 3");
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ struct Range {
|
|||
std::uint64_t allocationAddress;
|
||||
std::size_t allocationBytes;
|
||||
bool releasable = true;
|
||||
bool gpu = false;
|
||||
};
|
||||
|
||||
using Lease = std::vector<std::shared_ptr<const Range>>;
|
||||
|
|
@ -30,14 +31,14 @@ void GuestAllocationsRegisterImage_nid_postfix(void* mutation, const void* image
|
|||
void GuestAllocationsUnregisterImage_nid_postfix(void* mutation, const void* image);
|
||||
#endif
|
||||
void GuestAllocationsEnd_nid_postfix(void* mutation) noexcept;
|
||||
void GuestAllocationsAdd_nid_postfix(void* mutation, void* pointer, std::size_t bytes, bool readable, bool writable);
|
||||
void GuestAllocationsAdd_nid_postfix(void* mutation, void* pointer, std::size_t bytes, bool readable, bool writable, bool gpu);
|
||||
void GuestAllocationsRequireUnpinned_nid_postfix(void* mutation, const void* pointer, std::size_t bytes);
|
||||
void GuestAllocationsRequireAvailable_nid_postfix(void* mutation, const void* pointer, std::size_t bytes);
|
||||
bool GuestAllocationsCovers_nid_postfix(void* mutation, const void* pointer, std::size_t bytes);
|
||||
bool GuestAllocationsOverlaps_nid_postfix(void* mutation, const void* pointer, std::size_t bytes);
|
||||
Range GuestAllocationsFind_nid_postfix(void* mutation, const void* pointer);
|
||||
void GuestAllocationsRemove_nid_postfix(void* mutation, const void* pointer);
|
||||
void GuestAllocationsProtect_nid_postfix(void* mutation, const void* pointer, std::size_t bytes, bool readable, bool writable, const std::function<void()>& apply);
|
||||
void GuestAllocationsProtect_nid_postfix(void* mutation, const void* pointer, std::size_t bytes, bool readable, bool writable, bool gpu, const std::function<void()>& apply);
|
||||
void GuestAllocationsUnmap_nid_postfix(void* mutation, const void* pointer, std::size_t bytes, const std::function<void(const void*, std::size_t, const void*, bool)>& apply);
|
||||
Lease GuestAllocationsAcquire_nid_postfix();
|
||||
Lease GuestAllocationsAcquireAll_nid_postfix();
|
||||
|
|
@ -66,7 +67,7 @@ public:
|
|||
void RegisterImage(const void* image) { GuestAllocationsRegisterImage_nid_postfix(handle, image); }
|
||||
void UnregisterImage(const void* image) { GuestAllocationsUnregisterImage_nid_postfix(handle, image); }
|
||||
#endif
|
||||
void Add(void* pointer, std::size_t bytes, bool readable, bool writable) { GuestAllocationsAdd_nid_postfix(handle, pointer, bytes, readable, writable); }
|
||||
void Add(void* pointer, std::size_t bytes, bool readable, bool writable, bool gpu) { GuestAllocationsAdd_nid_postfix(handle, pointer, bytes, readable, writable, gpu); }
|
||||
void RequireUnpinned(const void* pointer, std::size_t bytes) const { GuestAllocationsRequireUnpinned_nid_postfix(handle, pointer, bytes); }
|
||||
void RequireAvailable(const void* pointer, std::size_t bytes) const { GuestAllocationsRequireAvailable_nid_postfix(handle, pointer, bytes); }
|
||||
bool Covers(const void* pointer, std::size_t bytes) const { return GuestAllocationsCovers_nid_postfix(handle, pointer, bytes); }
|
||||
|
|
@ -74,7 +75,7 @@ public:
|
|||
Range Find(const void* pointer) const { return GuestAllocationsFind_nid_postfix(handle, pointer); }
|
||||
void Remove(const void* pointer) { GuestAllocationsRemove_nid_postfix(handle, pointer); }
|
||||
void Unmap(const void* pointer, std::size_t bytes, const std::function<void(const void*, std::size_t, const void*, bool)>& apply) { GuestAllocationsUnmap_nid_postfix(handle, pointer, bytes, apply); }
|
||||
void Protect(const void* pointer, std::size_t bytes, bool readable, bool writable, const std::function<void()>& apply) { GuestAllocationsProtect_nid_postfix(handle, pointer, bytes, readable, writable, apply); }
|
||||
void Protect(const void* pointer, std::size_t bytes, bool readable, bool writable, bool gpu, const std::function<void()>& apply) { GuestAllocationsProtect_nid_postfix(handle, pointer, bytes, readable, writable, gpu, apply); }
|
||||
|
||||
private:
|
||||
void* handle;
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ void GuestAllocationsRegisterMainImage_nid_postfix(void*) {
|
|||
}
|
||||
#endif
|
||||
|
||||
void GuestAllocationsAdd_nid_postfix(void* mutation, void* pointer, std::size_t bytes, bool readable, bool writable) {
|
||||
void GuestAllocationsAdd_nid_postfix(void* mutation, void* pointer, std::size_t bytes, bool readable, bool writable, bool gpu) {
|
||||
recordChange(mutation, pointer, bytes);
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(pointer);
|
||||
require(address != 0 && bytes <= std::numeric_limits<std::uint64_t>::max() - address, "invalid guest allocation range");
|
||||
|
|
@ -254,7 +254,7 @@ void GuestAllocationsAdd_nid_postfix(void* mutation, void* pointer, std::size_t
|
|||
const auto& previous = *std::prev(next)->second;
|
||||
require(previous.address + previous.bytes <= address, "overlapping guest allocation");
|
||||
}
|
||||
ranges.emplace(address, std::make_shared<const Range>(Range{address, bytes, readable, writable, address, bytes}));
|
||||
ranges.emplace(address, std::make_shared<const Range>(Range{address, bytes, readable, writable, address, bytes, true, gpu}));
|
||||
}
|
||||
|
||||
[[noreturn]] void PinnedFailure(std::uintptr_t address, std::size_t bytes, const char* why) {
|
||||
|
|
@ -355,12 +355,12 @@ Range GuestAllocationsFind_nid_postfix(void*, const void* pointer) {
|
|||
if (exact != registry().ranges.end() && exact->second->allocationAddress == address && exact->second->allocationBytes == exact->second->bytes) {
|
||||
const auto& range = *exact->second;
|
||||
require(range.releasable, "guest image memory is not a releasable allocation");
|
||||
return {address, range.allocationBytes, range.readable, range.writable, address, range.allocationBytes, range.releasable};
|
||||
return {address, range.allocationBytes, range.readable, range.writable, address, range.allocationBytes, range.releasable, range.gpu};
|
||||
}
|
||||
for (const auto& [base, range] : registry().ranges) {
|
||||
if (range->allocationAddress == address) {
|
||||
require(range->releasable, "guest image memory is not a releasable allocation");
|
||||
return {address, range->allocationBytes, range->readable, range->writable, address, range->allocationBytes, range->releasable};
|
||||
return {address, range->allocationBytes, range->readable, range->writable, address, range->allocationBytes, range->releasable, range->gpu};
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("guest allocation is not registered");
|
||||
|
|
@ -381,7 +381,7 @@ void GuestAllocationsRemove_nid_postfix(void* mutation, const void* pointer) {
|
|||
|
||||
namespace {
|
||||
|
||||
std::map<std::uint64_t, std::shared_ptr<const Range>> replaceRange(const void* pointer, std::size_t bytes, bool remove, bool readable, bool writable) {
|
||||
std::map<std::uint64_t, std::shared_ptr<const Range>> replaceRange(const void* pointer, std::size_t bytes, bool remove, bool readable, bool writable, bool gpu) {
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(pointer);
|
||||
require(bytes != 0 && bytes <= std::numeric_limits<std::uint64_t>::max() - address, "invalid guest protection or unmap range");
|
||||
require(!writable || readable, "writable guest allocation must be readable");
|
||||
|
|
@ -395,12 +395,12 @@ std::map<std::uint64_t, std::shared_ptr<const Range>> replaceRange(const void* p
|
|||
if (base >= end) break;
|
||||
require(base <= cursor, "guest protection or unmap range has a hole");
|
||||
replacement.erase(base);
|
||||
const auto insert = [&](std::uint64_t first, std::uint64_t last, bool canRead, bool canWrite) {
|
||||
if (first < last) replacement.emplace(first, std::make_shared<const Range>(Range{first, static_cast<std::size_t>(last - first), canRead, canWrite, range.allocationAddress, range.allocationBytes, range.releasable}));
|
||||
const auto insert = [&](std::uint64_t first, std::uint64_t last, bool canRead, bool canWrite, bool gpuMapped) {
|
||||
if (first < last) replacement.emplace(first, std::make_shared<const Range>(Range{first, static_cast<std::size_t>(last - first), canRead, canWrite, range.allocationAddress, range.allocationBytes, range.releasable, gpuMapped}));
|
||||
};
|
||||
insert(base, std::max(base, address), range.readable, range.writable);
|
||||
if (!remove) insert(std::max(base, address), std::min(finish, end), readable, writable);
|
||||
insert(std::min(finish, end), finish, range.readable, range.writable);
|
||||
insert(base, std::max(base, address), range.readable, range.writable, range.gpu);
|
||||
if (!remove) insert(std::max(base, address), std::min(finish, end), readable, writable, gpu);
|
||||
insert(std::min(finish, end), finish, range.readable, range.writable, range.gpu);
|
||||
cursor = std::min(finish, end);
|
||||
}
|
||||
require(cursor == end, "guest protection or unmap range is not registered");
|
||||
|
|
@ -409,10 +409,10 @@ std::map<std::uint64_t, std::shared_ptr<const Range>> replaceRange(const void* p
|
|||
|
||||
}
|
||||
|
||||
void GuestAllocationsProtect_nid_postfix(void* mutation, const void* pointer, std::size_t bytes, bool readable, bool writable, const std::function<void()>& apply) {
|
||||
void GuestAllocationsProtect_nid_postfix(void* mutation, const void* pointer, std::size_t bytes, bool readable, bool writable, bool gpu, const std::function<void()>& apply) {
|
||||
GuestAllocationsRequireUnpinned_nid_postfix(mutation, pointer, bytes);
|
||||
recordChange(mutation, pointer, bytes);
|
||||
auto replacement = replaceRange(pointer, bytes, false, readable, writable);
|
||||
auto replacement = replaceRange(pointer, bytes, false, readable, writable, gpu);
|
||||
apply();
|
||||
registry().ranges.swap(replacement);
|
||||
}
|
||||
|
|
@ -438,7 +438,7 @@ void GuestAllocationsUnmap_nid_postfix(void* mutation, const void* pointer, std:
|
|||
const auto range = *containing;
|
||||
require(range.releasable, "guest image memory cannot be unmapped");
|
||||
const auto pieceEnd = std::min<std::uint64_t>(end, range.allocationAddress + range.allocationBytes);
|
||||
auto replacement = replaceRange(reinterpret_cast<const void*>(cursor), pieceEnd - cursor, true, false, false);
|
||||
auto replacement = replaceRange(reinterpret_cast<const void*>(cursor), pieceEnd - cursor, true, false, false, false);
|
||||
bool last = true;
|
||||
for (const auto& [base, entry] : replacement) {
|
||||
if (entry->allocationAddress == range.allocationAddress) last = false;
|
||||
|
|
|
|||
|
|
@ -210,7 +210,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);
|
||||
mutation.Add(pointer, bytes, true, true, true);
|
||||
} catch (...) {
|
||||
rawFree(raw, blockBytes);
|
||||
throw;
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ static int mprotect(void* addr, size_t len, int prot) {
|
|||
namespace {
|
||||
|
||||
constexpr int GuestMapFixedFlag = 0x10;
|
||||
constexpr int GuestProtGpuReadWrite = 0x30;
|
||||
|
||||
#if defined(__linux__)
|
||||
void* MapAtOrAbove(std::uintptr_t start, size_t len, int prot, size_t alignment) {
|
||||
|
|
@ -494,7 +495,7 @@ bool RemapFixedIntoRegistered(GuestAllocations::Mutation& mutation, void* addr,
|
|||
ValidateRange(addr, len, PS5_PAGE_SIZE);
|
||||
Trace("remap fixed %p+0x%zx prot=0x%x phys=0x%llx", addr, len, prot, static_cast<long long>(physStart));
|
||||
const auto nativeProtection = LinuxProtFromSce(prot);
|
||||
mutation.Protect(addr, len, (prot & 3) != 0, (prot & 2) != 0, [&] {
|
||||
mutation.Protect(addr, len, (prot & 3) != 0, (prot & 2) != 0, (prot & GuestProtGpuReadWrite) != 0, [&] {
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(addr);
|
||||
std::lock_guard lock(g_directLock);
|
||||
if (physStart >= 0) {
|
||||
|
|
@ -742,7 +743,7 @@ int DoMapDirect(void** addr, size_t len, int prot, int flags, int64_t physStart,
|
|||
void* mapped = MapAligned(*addr, len, PROT_NONE, flags, alignment);
|
||||
try {
|
||||
AddMapping(reinterpret_cast<std::uintptr_t>(mapped), len, static_cast<std::uint64_t>(physStart), LinuxProtFromSce(prot));
|
||||
mutation.Add(mapped, len, (prot & 3) != 0, (prot & 2) != 0);
|
||||
mutation.Add(mapped, len, (prot & 3) != 0, (prot & 2) != 0, (prot & GuestProtGpuReadWrite) != 0);
|
||||
} catch (...) {
|
||||
EraseMappings(reinterpret_cast<std::uintptr_t>(mapped), reinterpret_cast<std::uintptr_t>(mapped) + len);
|
||||
Unmap(mapped, len);
|
||||
|
|
@ -768,7 +769,7 @@ int DoMapAnon(void** addr, size_t len, int prot, int flags, size_t alignment) {
|
|||
ReplaceFixedOverlap(mutation, *addr, len, flags);
|
||||
void* mapped = MapAligned(*addr, len, LinuxProtFromSce(prot), flags, alignment);
|
||||
try {
|
||||
mutation.Add(mapped, len, (prot & 3) != 0, (prot & 2) != 0);
|
||||
mutation.Add(mapped, len, (prot & 3) != 0, (prot & 2) != 0, (prot & GuestProtGpuReadWrite) != 0);
|
||||
} catch (...) {
|
||||
Unmap(mapped, len);
|
||||
throw;
|
||||
|
|
@ -821,7 +822,7 @@ int DoMprotect(const void* addr, size_t len, int prot) {
|
|||
#else
|
||||
mutation.RegisterMainImage();
|
||||
#endif
|
||||
mutation.Protect(pointer, bytes, (prot & 3) != 0, (prot & 2) != 0, [&] {
|
||||
mutation.Protect(pointer, bytes, (prot & 3) != 0, (prot & 2) != 0, (prot & GuestProtGpuReadWrite) != 0, [&] {
|
||||
if (mprotect(const_cast<void*>(pointer), bytes, nativeProtection) != 0) throw std::system_error(errno, std::generic_category(), "mprotect failed");
|
||||
});
|
||||
RecordProtection(pointer, bytes, prot);
|
||||
|
|
@ -881,7 +882,7 @@ int DoReserveVirtual(void** addr, size_t len, int flags, size_t alignment) {
|
|||
constexpr int GuestMapNoCoalesce = 0x400000;
|
||||
void* mapped = MapAligned(fixed ? *addr : nullptr, len, PROT_NONE, fixed ? GuestMapFixedFlag | (flags & GuestMapNoCoalesce) : 0, alignment);
|
||||
try {
|
||||
mutation.Add(mapped, len, false, false);
|
||||
mutation.Add(mapped, len, false, false, false);
|
||||
} catch (...) {
|
||||
Unmap(mapped, len);
|
||||
throw;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "prx/libkernel/File/include/FileFlags.hpp"
|
||||
#include "prx/libkernel/KernelErrors.hpp"
|
||||
#include "prx/libkernel/DirectMemory/DirectMemory.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include "SceTypes.hpp"
|
||||
|
|
@ -423,6 +424,48 @@ static void CheckDirectMemoryGpuProtBits() {
|
|||
Require(sceKernelReleaseDirectMemory(phys, page) == 0);
|
||||
}
|
||||
|
||||
static bool GpuMapped(const void* pointer) {
|
||||
GuestAllocations::Mutation mutation;
|
||||
return mutation.Find(pointer).gpu;
|
||||
}
|
||||
|
||||
static void CheckGpuAccessFollowsProtection() {
|
||||
constexpr std::size_t page = 0x4000;
|
||||
std::int64_t phys = 0;
|
||||
Require(sceKernelAllocateDirectMemory(0, 0x7fffffffffll, page * 2, 0, 0, &phys) == 0);
|
||||
void* cpu = nullptr;
|
||||
Require(sceKernelMapDirectMemory(&cpu, page, 3, 0, phys, 0) == 0);
|
||||
Require(!GpuMapped(cpu));
|
||||
void* gpu = nullptr;
|
||||
Require(sceKernelMapDirectMemory(&gpu, page, 0x32, 0, phys + static_cast<std::int64_t>(page), 0) == 0);
|
||||
Require(GpuMapped(gpu));
|
||||
Require(sceKernelMprotect(cpu, page, 0x13) == 0);
|
||||
Require(GpuMapped(cpu));
|
||||
Require(sceKernelMprotect(gpu, page, 3) == 0);
|
||||
Require(!GpuMapped(gpu));
|
||||
static int imageProbe = 0;
|
||||
const auto probe = reinterpret_cast<std::uintptr_t>(&imageProbe);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.RegisterMainImage();
|
||||
}
|
||||
{
|
||||
const auto lease = GuestAllocations::GuestAllocationsAcquire_nid_postfix();
|
||||
const auto image = std::find_if(lease.begin(), lease.end(), [&](const auto& range) { return probe >= range->address && probe - range->address < range->bytes; });
|
||||
Require(image != lease.end() && !(*image)->releasable && !(*image)->gpu);
|
||||
}
|
||||
Require(sceKernelMunmap(cpu, page) == 0);
|
||||
Require(sceKernelMunmap(gpu, page) == 0);
|
||||
Require(sceKernelReleaseDirectMemory(phys, page * 2) == 0);
|
||||
void* flexible = nullptr;
|
||||
Require(sceKernelMapNamedFlexibleMemory(&flexible, page, 3, 0, "cpu") == 0);
|
||||
Require(!GpuMapped(flexible));
|
||||
Require(sceKernelMunmap(flexible, page) == 0);
|
||||
Require(sceKernelMapNamedFlexibleMemory(&flexible, page, 0x33, 0, "gpu") == 0);
|
||||
Require(GpuMapped(flexible));
|
||||
Require(sceKernelMunmap(flexible, page) == 0);
|
||||
}
|
||||
|
||||
static void CheckFixedVirtualReservation() {
|
||||
constexpr std::size_t page = 0x4000;
|
||||
void* probe = nullptr;
|
||||
|
|
@ -603,7 +646,7 @@ static void CheckGuestModuleImageProtection() {
|
|||
Require(!RegisteredGuestRange(target, page));
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(target, page, true, true);
|
||||
mutation.Add(target, page, true, true, false);
|
||||
mutation.Remove(target);
|
||||
}
|
||||
|
||||
|
|
@ -1406,6 +1449,7 @@ int main() {
|
|||
CheckReleaseDirectMemoryRejectsInvalidRanges();
|
||||
CheckFixedMappingReplacesPartialOverlap();
|
||||
CheckDirectMemoryGpuProtBits();
|
||||
CheckGpuAccessFollowsProtection();
|
||||
CheckFixedVirtualReservation();
|
||||
CheckReservedRangeIsNotCommitted();
|
||||
CheckNoOverwriteRefusesLiveMapping();
|
||||
|
|
|
|||
Loading…
Reference in New Issue