From 1561ee116007e720315ecc64f6047ae2e5fbbec0 Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Thu, 14 May 2026 15:31:28 +0200 Subject: [PATCH] fix: reliability improvements in WinServer/IPC subsystems --- kernel/src/Api/WinServer.cpp | 6 +++--- kernel/src/Ipc/Ipc.cpp | 25 ++++++++++--------------- kernel/src/Ipc/Ipc.hpp | 3 ++- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/kernel/src/Api/WinServer.cpp b/kernel/src/Api/WinServer.cpp index fde0109..8232911 100644 --- a/kernel/src/Api/WinServer.cpp +++ b/kernel/src/Api/WinServer.cpp @@ -142,7 +142,7 @@ namespace WinServer { FillSurfaceLocked(snapshot, w, h, InitialWindowPixel); uint64_t userVa = 0; - if (Ipc::MapSurfaceForPid(live, ownerPid, ownerPml4, heapNext, userVa) != 0) { + if (Ipc::MapSurfaceForPid(live, ownerPid, ownerPml4, heapNext, userVa, false) != 0) { Ipc::ReleaseMailbox(mailbox, true, true); Ipc::ReleaseSurface(snapshot); Ipc::ReleaseSurface(live); @@ -242,7 +242,7 @@ namespace WinServer { if (!slot.used || slot.snapshotSurface == nullptr) return 0; uint64_t outVa = 0; - if (Ipc::MapSurfaceForPid(slot.snapshotSurface, callerPid, callerPml4, heapNext, outVa) != 0) { + if (Ipc::MapSurfaceForPid(slot.snapshotSurface, callerPid, callerPml4, heapNext, outVa, false) != 0) { return 0; } return outVa; @@ -294,7 +294,7 @@ namespace WinServer { Ipc::RetainSurface(newSnapshot); uint64_t newOwnerVa = 0; - if (Ipc::MapSurfaceForPid(newLive, callerPid, ownerPml4, heapNext, newOwnerVa) != 0) { + if (Ipc::MapSurfaceForPid(newLive, callerPid, ownerPml4, heapNext, newOwnerVa, false) != 0) { Ipc::ReleaseSurface(newSnapshot); Ipc::ReleaseSurface(newLive); return -1; diff --git a/kernel/src/Ipc/Ipc.cpp b/kernel/src/Ipc/Ipc.cpp index 9c91e87..25ede95 100644 --- a/kernel/src/Ipc/Ipc.cpp +++ b/kernel/src/Ipc/Ipc.cpp @@ -1806,7 +1806,8 @@ namespace Ipc { return 0; } - int MapSurfaceForPid(Surface* surface, int pid, uint64_t pml4Phys, uint64_t& heapNext, uint64_t& outVa) { + int MapSurfaceForPid(Surface* surface, int pid, uint64_t pml4Phys, uint64_t& heapNext, + uint64_t& outVa, bool reserveGrowthRange) { if (surface == nullptr) return -1; int slot = SlotForPid(pid); @@ -1862,20 +1863,14 @@ namespace Ipc { g_surfaceMaps[slot][mapIdx].numPages = numPages; surface->refs++; // inlined RetainRawObject — we already hold surface->lock - // Reserve the full surface address-range cap, not just the currently - // mapped pages. ResizeSurface can grow this surface up to - // MaxSurfacePages, and its grow path extends the existing VA range - // in-place by mapping new pages at baseVa + p*0x1000 for p beyond the - // original size. If we only bumped heapNext by numPages*0x1000, any - // subsequent mapping (another surface, heap allocation, etc.) would - // sit at baseVa + numPages*0x1000 -- and a later grow would silently - // overwrite its PTEs. Reserving MaxSurfacePages*0x1000 (32 MiB) of - // VA per mapping is cheap: 47-bit user VA gives 128 TiB of headroom, - // and at most MaxSurfaceMapsPerProcess (64) mappings per process - // means at most 2 GiB of reserved VA per process. Page tables are - // only populated for pages actually mapped; unused VA in the - // reservation costs nothing beyond the address-space slot. - heapNext += (uint64_t)MaxSurfacePages * 0x1000ULL; + // Generic IPC surfaces can grow in place through ResizeSurface(), so + // their mapping must reserve the maximum VA range that a later grow + // can populate. Window-server surfaces are replaced rather than grown + // in place, so callers can opt out and avoid burning 32 MiB of process + // VA on every window map/remap during a long desktop session. + uint32_t reservedPages = reserveGrowthRange ? MaxSurfacePages : numPages; + if (reservedPages < numPages) reservedPages = numPages; + heapNext += (uint64_t)reservedPages * 0x1000ULL; outVa = baseVa; surface->lock.Release(); return 0; diff --git a/kernel/src/Ipc/Ipc.hpp b/kernel/src/Ipc/Ipc.hpp index f225876..87dba67 100644 --- a/kernel/src/Ipc/Ipc.hpp +++ b/kernel/src/Ipc/Ipc.hpp @@ -135,7 +135,8 @@ namespace Ipc { uint32_t fillPixel); uint64_t MapSurfaceHandle(int handle); int ResizeSurfaceHandle(int handle, uint64_t newSize); - int MapSurfaceForPid(Surface* surface, int pid, uint64_t pml4Phys, uint64_t& heapNext, uint64_t& outVa); + int MapSurfaceForPid(Surface* surface, int pid, uint64_t pml4Phys, uint64_t& heapNext, + uint64_t& outVa, bool reserveGrowthRange = true); int UnmapSurfaceForPid(Surface* surface, int pid, uint64_t pml4Phys); ProcessObject* GetProcessObject(int pid);