diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-30 00:54:09 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-30 00:54:37 -0400 |
| commit | d22a03efcd0aeddaa7d0d2ca47bd345f6ecf7752 (patch) | |
| tree | 87ee2316a8762f365eaa67e38dda72bb3a371bd5 /src/core/hle/kernel | |
| parent | b937805eb573cbad52fc698fd149752eae0ddc81 (diff) | |
kernel: clear the fastmem arena when the application process is closed
Loading a Switch 2 game after another one in the same window hung or
crashed it at boot. The first game's process still had 55-60 references
at kernel shutdown, so it was never finalized and its memory stayed
mapped in the fastmem arena. The next game's mappings at the same
addresses then failed ("Failed to split placeholder" / "Failed to map
placeholder"), and it ran on the first game's memory: Mario Kart World
loaded after another Switch 2 game jumped to a garbage address from
rtld, or hung.
Detach the closed process from the arena (a late finalize must not
unmap the next game's memory), unmap the whole arena, and log when the
process was still referenced.
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b437dd4b4e..f006d129a7 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -22,6 +22,7 @@ #include "core/arm/arm_interface.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" +#include "core/device_memory.h" #include "core/core_timing.h" #include "core/cpu_manager.h" #include "core/hardware_properties.h" @@ -138,8 +139,21 @@ struct KernelCore::Impl { CloseServices(); if (application_process) { + // A process still referenced here is never finalized, so its memory stays mapped in + // the fastmem arena, and the next game's mappings at the same addresses failed: it ran + // on the old game's memory and crashed or hung at boot (a Switch 2 game left its + // process with 55-60 references). Detach the process from the arena, so a late + // finalize can't unmap the next game's memory, and clear the arena. + const u32 references = application_process->GetReferenceCount(); + application_process->GetPageTable().GetImpl().fastmem_arena = nullptr; application_process->Close(system.Kernel()); application_process = nullptr; + if (references > 1) { + LOG_WARNING(Kernel, "Application process still had {} references at shutdown", + references); + } + auto& arena = system.DeviceMemory().buffer; + arena.Unmap(0, arena.VirtualSize(), false); } next_object_id = 0; |
