Windows: speculative read faults resume before the GPU page tracking; the guest pool is committed at boot and retried

From HayatoG's iss_pc:
- ea09b1c: a speculative guest read fault resumes its recovery point before the GPU page
  tracking, as on Linux; resolving the tracking first could wait on the GPU thread while it
  waits on that worker (freeze inside the GPU page fault handler).
- fadd416: the guest pool is created before the GPU driver and the shader warm-up raise the
  process's commit, and error 1450/1455 is retried for about 5 s (a system-managed page file
  grows after a refused commit); the last message names the commit limit and what to do. It
  matters more now that native 2K / 4K enlarge the pool.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Eij6gW2nnTUK9BowHuBVZZ
This commit is contained in:
Claude committed 2026-10-27 23:29:15 -03:00
1 parent c2a6853e31
commit dc3dc52c6e
3 files changed
+52 -4

No files matched your search

+17 -2
View File
@@ -218,10 +218,13 @@ static LONG CALLBACK vectored_fault(EXCEPTION_POINTERS *info) {
}
if (code==EXCEPTION_ACCESS_VIOLATION && record->NumberParameters>=2) {
/* GPU page tracking (write-protected guest pages) is resolved first. */
if (gpu_enabled && issngpu_handle_fault(info,(void *)record->ExceptionInformation[1])) return EXCEPTION_CONTINUE_EXECUTION;
if (runtime_fault_recover) {
/* A speculative guest memory read (GPU draw preparation) faulted: the thread resumes
* in issn_longjmp, outside the exception dispatcher, back at its recovery point. */
* in issn_longjmp, outside the exception dispatcher, back at its recovery point. This
* comes before the GPU page tracking, as on Linux: with precise readbacks the page may
* be read-protected because the GPU wrote it, and its readback waits on the GPU
* thread, which can be waiting on this worker (HayatoG's iss_pc ea09b1c: the freeze
* "inside GPU page fault handler"). */
unsigned long long *buffer=*runtime_fault_recover;
runtime_fault_recover=NULL;
CONTEXT *c=info->ContextRecord;
@@ -231,6 +234,8 @@ static LONG CALLBACK vectored_fault(EXCEPTION_POINTERS *info) {
c->Rip=(DWORD64)(uintptr_t)issn_longjmp;
return EXCEPTION_CONTINUE_EXECUTION;
}
/* GPU page tracking (write-protected guest pages). */
if (gpu_enabled && issngpu_handle_fault(info,(void *)record->ExceptionInformation[1])) return EXCEPTION_CONTINUE_EXECUTION;
}
if (code==EXCEPTION_ACCESS_VIOLATION || code==EXCEPTION_ILLEGAL_INSTRUCTION || code==EXCEPTION_PRIV_INSTRUCTION ||
code==EXCEPTION_STACK_OVERFLOW || code==EXCEPTION_INT_DIVIDE_BY_ZERO || code==EXCEPTION_DATATYPE_MISALIGNMENT) {
@@ -1121,6 +1126,16 @@ int main(int argc, char **argv) {
if (procparam) memcpy(&sdk,image+procparam+16,8); /* procparam: size, magic, count, sdk_version */
IssnGpuConfig gpu={title,serial,user_dir ? user_dir : "user",(uint32_t)sdk,attributes,1920,1080,(uint64_t)(uintptr_t)image,
app0,app_ver};
#ifdef _WIN32
/* issn: the guest pool is committed before the GPU driver and the shader warm-up raise the
* process's commit (HayatoG's iss_pc fadd416); a failure stops with what to do. */
if (runtime_memory_create_pool()) {
printf("ERROR: the game's memory could not be reserved (see the Runtime line above): make the Windows "
"page file larger or choose a lower Resolution.\n");
fflush(NULL);
_exit(22);
}
#endif
gpu_enabled=1; /* page tracking starts while the rasterizer registers guest memory */
if (issngpu_init(&gpu)) fail("GPU initialization failed");
printf("GPU: window and Vulkan presenter ready; SDK 0x%08x, %u HLE symbols\n",(unsigned)sdk,issngpu_symbol_count());
+2
View File
@@ -77,6 +77,8 @@ int32_t runtime_guest_errno(int host_errno);
void *runtime_low_map(size_t size, int prot);
/* Windows: reserves the PS4 user address range as a placeholder (no-op elsewhere). */
void runtime_memory_reserve(void);
/* issn: creates the guest memory pool now (Windows: before the GPU raises the commit); 0 = ok. */
int runtime_memory_create_pool(void);
uintptr_t runtime_ajm_resolve(const char *name);
void runtime_ajm_report(void);
/* AjmDecMp3ParseFrame (guest layout). */
+33 -2
View File
@@ -271,12 +271,36 @@ static int host_protect(uintptr_t address, uint64_t size, int prot) {
/* Released pages read as zero when reused, like the memfd's punched holes. */
static void host_discard(uint64_t phys, uint64_t size) { memset(backing_base+phys,0,size); }
/* Direct memory occupies [0,POOL_SIZE) of the section, flexible memory [POOL_SIZE,+FLEX_SPAN). */
/* issn: a system-managed page file grows only after a commit fails, so a refused commit is tried
* again for a few seconds, and the pool is created at boot (runtime_memory_create_pool), before
* the GPU driver and the shader warm-up raise the process's commit (HayatoG's iss_pc fadd416:
* error 1450 on a 16 GB PC with a small page file). Native 2K / 4K make the pool larger. */
static int pool(void) {
static int failed;
if (backing_base) return 0;
if (failed) return -1;
runtime_memory_reserve();
uint64_t bytes=POOL_SIZE+FLEX_SPAN;
section=CreateFileMapping2(INVALID_HANDLE_VALUE,NULL,FILE_MAP_ALL_ACCESS,PAGE_EXECUTE_READWRITE,SEC_COMMIT,bytes,NULL,NULL,0);
if (!section) { fprintf(stderr,"Runtime: cannot create %" PRIu64 " MiB of guest memory (error %lu); is the page file large enough?\n",bytes>>20,GetLastError()); return -1; }
DWORD error=0;
for (int attempt=0; attempt<6; ++attempt) {
if (attempt) Sleep(1000);
section=CreateFileMapping2(INVALID_HANDLE_VALUE,NULL,FILE_MAP_ALL_ACCESS,PAGE_EXECUTE_READWRITE,SEC_COMMIT,bytes,NULL,NULL,0);
if (section) break;
error=GetLastError();
if (error!=ERROR_NO_SYSTEM_RESOURCES && error!=ERROR_COMMITMENT_LIMIT) break;
fprintf(stderr,"Runtime: %" PRIu64 " MiB of guest memory not available yet (error %lu), attempt %d of 6\n",bytes>>20,error,attempt+1);
}
if (!section) {
MEMORYSTATUSEX status={.dwLength=sizeof status};
GlobalMemoryStatusEx(&status);
fprintf(stderr,"Runtime: cannot create %" PRIu64 " MiB of guest memory (error %lu); is the page file large enough? "
"Commit limit %llu MiB, %llu MiB free. Set a custom page file (16384 MB initial, 24576 MB maximum) in "
"SystemPropertiesAdvanced > Performance > Advanced > Virtual memory and restart Windows, or choose a "
"lower Resolution.\n",
bytes>>20,error,(unsigned long long)(status.ullTotalPageFile>>20),(unsigned long long)(status.ullAvailPageFile>>20));
failed=1;
return -1;
}
backing_base=MapViewOfFile3(section,GetCurrentProcess(),NULL,0,bytes,0,PAGE_READWRITE,NULL,0);
return backing_base ? 0 : -1;
}
@@ -450,6 +474,13 @@ static int direct_range_allocated(uint64_t phys, uint64_t size) {
return 1;
}
/* Creates the guest pool at boot (see pool()); 0 on success. */
int runtime_memory_create_pool(void) {
write_lock();
int result=pool();
write_unlock();
return result;
}
static ABI uint64_t direct_size(void) { return POOL_SIZE; }
static ABI int32_t direct_allocate(int64_t low, int64_t high, uint64_t size,
uint64_t alignment, int type, int64_t *out) {