Files
NX2navi/tests/platform_bulk_write_test.c
chrg6 4d12238e69 Let a shadow write-back clear the write watch's protection of its range in one call on Linux (shadow_bulk_write = 1).
On Linux the write watch protects pages, so a write-back from shadow storage into guest memory took a fault
at the first store into every page. plat_mem_prepare_write clears the protection of a range with one
UFFDIO_WRITEPROTECT call; the pages count as written, as they would after the faults. Off by default;
Windows has nothing to clear.

Pull request #327 by theurbanninja1993-sketch (a draft on GitHub). The platform function and its Linux
test are taken as they are. The call moved: the write-back it was written for is now shadow_write_back in
runtime/vk_memory.c (a file other sessions are changing), where it covers the runs of pages a submission
changed, and the setting is registered in cfg.c and described in nx2navi.ini.example, which also says
that the lazy write-back stays off with shadow storage.

The Windows files compile; the Linux code and its test are not compiled or run here.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 06:31:27 -05:00

33 lines
1.7 KiB
C

// plat_mem_prepare_write on Linux (runtime/platform/linux.c): every page of a prepared range counts as written, a
// reset leaves it clean, and a later store to one page is still seen. No game files. Build and run from the
// repository root:
// clang -O2 -ffunction-sections -fdata-sections -Iruntime -c runtime/platform/linux.c -o /tmp/plat.o
// clang -O2 -Wall -Iruntime tests/platform_bulk_write_test.c /tmp/plat.o -Wl,--gc-sections -lpthread -ldl -o /tmp/bulk
// /tmp/bulk (exit 77: the write watch is not available on this kernel)
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "platform/platform.h"
int main(void) {
const uint64_t a = 0x6000000000ull, n = 4 * 4096;
uint64_t pages[4];
assert(plat_mem_reserve(a, n, 1));
assert(plat_mem_commit(a, n));
memset((void *)(uintptr_t)a, 0, n);
uint64_t count = plat_mem_written(a, n, pages, 4, 1);
if (count == UINT64_MAX) { puts("SKIP: asynchronous write watch unavailable"); return 77; }
assert(plat_mem_written(a, n, pages, 4, 0) == 0);
assert(plat_mem_prepare_write(a + 7, n - 14));
memset((void *)(uintptr_t)(a + 7), 0x5a, n - 14);
assert(plat_mem_written(a, n, pages, 4, 1) == 4);
for (unsigned i = 0; i < 4; i++) assert(pages[i] == a + i * 4096);
assert(plat_mem_written(a, n, pages, 4, 0) == 0);
*(volatile unsigned char *)(uintptr_t)(a + 2 * 4096) = 0xa5;
assert(plat_mem_written(a, n, pages, 4, 1) == 1 && pages[0] == a + 2 * 4096);
assert(!plat_mem_prepare_write(a, 0));
assert(!plat_mem_prepare_write(UINT64_MAX - 7, 16));
puts("bulk write watch: full range tracked, reset clean, subsequent single-page write tracked");
return 0;
}