diff --git a/core/libs/prx/libSceFiber/Export.cpp b/core/libs/prx/libSceFiber/Export.cpp index 50c808a96..83572e7d1 100644 --- a/core/libs/prx/libSceFiber/Export.cpp +++ b/core/libs/prx/libSceFiber/Export.cpp @@ -330,6 +330,7 @@ int32_t APS5_VABI _sceFiberInitializeImpl_nid_postfix(FiberObject* object, const if (addr_context == nullptr) return SCE_FIBER_ERROR_INVALID; if (size_context < FIBER_MIN_CONTEXT_SIZE) return SCE_FIBER_ERROR_RANGE; auto* fiber = reinterpret_cast(object); + if (fiber->magic == FIBER_MAGIC) UnpinStack(fiber->context, fiber->contextSize); std::memset(object, 0, FIBER_OBJECT_SIZE); fiber->magic = FIBER_MAGIC; fiber->state.store(FiberState::Idle, std::memory_order_relaxed); diff --git a/core/libs/tests/GuestMemory.cpp b/core/libs/tests/GuestMemory.cpp index 2fe9b8b06..8dee5f167 100644 --- a/core/libs/tests/GuestMemory.cpp +++ b/core/libs/tests/GuestMemory.cpp @@ -672,6 +672,49 @@ static void CheckSharedWriteTracking() { #endif } +static void CheckPinnedSharedPages() { +#ifdef _WIN32 + constexpr std::size_t page = 0x4000; + std::int64_t phys = 0; + Require(sceKernelAllocateDirectMemory(0, 0x7fffffffffll, page * 3, 0, 0, &phys) == 0); + void* mapped = nullptr; + Require(sceKernelMapDirectMemory(&mapped, page * 3, 3, 0, phys, 0) == 0); + auto* bytes = static_cast(mapped); + const auto collect = [&] { + std::array pages{}; + std::size_t count = pages.size(); + Require(GuestArena::GuestArenaCollectWrites_nid_postfix(reinterpret_cast(mapped), page * 3, pages.data(), &count, true)); + return count; + }; + const auto protection = [&](std::size_t offset) { + MEMORY_BASIC_INFORMATION info{}; + Require(VirtualQuery(const_cast(bytes + offset), &info, sizeof(info)) == sizeof(info)); + return info.Protect; + }; + collect(); + Require(collect() == 0); + Require(protection(0) == PAGE_READONLY && protection(page) == PAGE_READONLY); + GuestArena::GuestArenaPinWritable_nid_postfix(const_cast(bytes + page), page); + Require(protection(page) == PAGE_READWRITE && protection(0) == PAGE_READONLY && protection(page * 2) == PAGE_READONLY); + Require(collect() == 4); + Require(collect() == 4); + Require(protection(page) == PAGE_READWRITE); + bytes[page + 8] = 7; + bytes[0] = 9; + Require(collect() == 8); + Require(collect() == 4); + Require(protection(0) == PAGE_READONLY && protection(page) == PAGE_READWRITE); + GuestArena::GuestArenaUnpinWritable_nid_postfix(const_cast(bytes + page), page); + collect(); + Require(collect() == 0); + Require(protection(page) == PAGE_READONLY); + bytes[page + 8] = 11; + Require(collect() == 4); + Require(sceKernelMunmap(mapped, page * 3) == 0); + Require(sceKernelReleaseDirectMemory(phys, page * 3) == 0); +#endif +} + static void CheckReadsIntoSharedWriteTracking() { #ifdef _WIN32 constexpr std::size_t page = 0x4000; @@ -937,6 +980,7 @@ int main() { #endif CheckSharedWriteTracking(); CheckReadsIntoSharedWriteTracking(); + CheckPinnedSharedPages(); #if defined(__linux__) CheckWriteWatch(); CheckDirectMemoryWriteWatch();