diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index 08a9b88078..d3bde4a164 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -1373,8 +1373,9 @@ void PSPSaveDialog::DoState(PointerWrap &p) { // value is never SAVEIO_PENDING. Without this, loading a state taken // while a savedata operation was in flight would restart the operation // instead of resuming from its recorded status. Version 4 keeps the - // results of a finished operation that haven't been taken yet. - auto s = p.Section("PSPSaveDialog", 1, 5); + // results of a finished operation that haven't been taken yet. Version 6 keeps originalRequest, + // or the first Update after a load would reload the request and lose results kept in request. + auto s = p.Section("PSPSaveDialog", 1, 6); if (!s) { return; } @@ -1407,6 +1408,18 @@ void PSPSaveDialog::DoState(PointerWrap &p) { if (s == 4) { DoStateOldPendingWrites(p); } + if (s >= 6) { + Do(p, originalRequest); + } else if (p.mode == p.MODE_READ) { + // Best guess: what the game's request holds now, the way Update reads it. + memset(&originalRequest, 0, sizeof(originalRequest)); + if (Memory::IsValidRange(requestAddr, 4)) { + const u32 size = std::min((u32)sizeof(originalRequest), Memory::ReadUnchecked_U32(requestAddr)); + if (Memory::IsValidRange(requestAddr, size)) { + Memory::Memcpy(&originalRequest, requestAddr, size); + } + } + } } pspUtilityDialogCommon *PSPSaveDialog::GetCommonParam() { diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 15eeec6a21..bb525627ae 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -471,6 +471,9 @@ struct SceKernelSMOption { static int actionAfterModule; static std::set loadedModules; +// Set once we've seen a PSP_MODULE_VSH_MODE module load (i.e. we're booting the VSH rather +// than a game), and reset on the next __KernelLoadExec. See ShouldHLEModuleForLoad below. +static bool g_runningVSH = false; // STATE END ////////////////////////////////////////////////////////////////////////// @@ -479,7 +482,7 @@ static void __KernelModuleInit() { } void __KernelModuleDoState(PointerWrap &p) { - auto s = p.Section("sceKernelModule", 1, 2); + auto s = p.Section("sceKernelModule", 1, 3); if (!s) return; @@ -491,6 +494,19 @@ void __KernelModuleDoState(PointerWrap &p) { if (s >= 2) { Do(p, loadedModules); } + if (s >= 3) { + Do(p, g_runningVSH); + } else if (p.mode == p.MODE_READ) { + // Derive it the way the loader sets it. + g_runningVSH = false; + for (SceUID moduleId : loadedModules) { + u32 error; + PSPModule *module = kernelObjects.Get(moduleId, error); + if (module && ((module->nm.attribute & PSP_MODULE_VSH_MODE) != 0 || equals(module->nm.name, "vsh_module"))) { + g_runningVSH = true; + } + } + } if (p.mode == p.MODE_READ) { u32 error; @@ -1120,10 +1136,6 @@ enum : u32 { ELF_MAGIC = 0x464c457f, }; -// Set once we've seen a PSP_MODULE_VSH_MODE module load (i.e. we're booting the VSH rather -// than a game), and reset on the next __KernelLoadExec. See ShouldHLEModuleForLoad below. -static bool g_runningVSH = false; - // A few flash0 modules (VSH's own bridge/UI/utility libraries) should only ever be genuinely // loaded - rather than faked via any HLE implementation we may have for them - once we know // we're actually running the VSH. A regular game never legitimately loads these, so this only diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 87f7e660d2..c2f0f6371a 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -364,6 +364,10 @@ void __MpegInit() { isMpegInit = false; mpegLibVersion = 0x010A; streamIdGen = 1; + useRingbufferPutCallbackMulti = true; + sceMpegAvcResourceAddr = 0; + sceMpegAvcResourceDataAddr = 0; + sceMpegAvcResourceFlags = 0; actionPostPut = __KernelRegisterActionType(PostPutAction::Create); #ifdef USE_FFMPEG @@ -377,7 +381,7 @@ void __MpegInit() { } void __MpegDoState(PointerWrap &p) { - auto s = p.Section("sceMpeg", 1, 4); + auto s = p.Section("sceMpeg", 1, 5); if (!s) return; @@ -394,6 +398,7 @@ void __MpegDoState(PointerWrap &p) { useRingbufferPutCallbackMulti = false; ringbufferPutPacketsAdded = 0; } else { + useRingbufferPutCallbackMulti = true; Do(p, ringbufferPutPacketsAdded); } if (s < 4) { @@ -411,6 +416,18 @@ void __MpegDoState(PointerWrap &p) { __KernelRestoreActionType(actionPostPut, PostPutAction::Create); Do(p, g_mpegCtxs); + + if (s >= 5) { + Do(p, sceMpegAvcResourceFlags); + } else { + sceMpegAvcResourceFlags = 0; + } + if (p.mode == p.MODE_READ) { + // Constant for now, see sceMpegAvcResourceInit. + const bool inited = (sceMpegAvcResourceFlags & MPEG_AVC_RESOURCE_FLAG) != 0; + sceMpegAvcResourceAddr = inited ? 0x10000000 : 0; + sceMpegAvcResourceDataAddr = inited ? sceMpegAvcResourceAddr + 8 : 0; + } } void __MpegShutdown() { diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 589a6bc1a3..2e6a22fee1 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -29,6 +29,7 @@ #include "Common/System/OSD.h" #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeDeque.h" #include "Common/Serialize/SerializeMap.h" #include "Common/Data/Format/JSONReader.h" #include "Common/System/System.h" @@ -707,7 +708,7 @@ void netValidateLoopMemory() { // This feels like a dubious proposition, mostly... void __NetDoState(PointerWrap &p) { - auto s = p.Section("sceNet", 1, 6); + auto s = p.Section("sceNet", 1, 7); if (!s) return; @@ -763,6 +764,18 @@ void __NetDoState(PointerWrap &p) { netApctlInfoId = 0; NetApctl_InitDefaultInfo(); } + if (s >= 7) { + // The state only moves on when an event is processed, and each queues the next, so a + // connect in progress would never finish without them. + std::lock_guard apctlGuard(apctlEvtMtx); + Do(p, apctlEvents); + // Allocated from user memory, which the load just replaced. + Do(p, apctlProdCodeAddr); + } else if (p.mode == p.MODE_READ) { + std::lock_guard apctlGuard(apctlEvtMtx); + apctlEvents.clear(); + apctlProdCodeAddr = 0; + } if (p.mode == p.MODE_READ) { // Let's not change "Inited" value when Loading SaveState in the middle of multiplayer to prevent memory & port leaks @@ -770,8 +783,6 @@ void __NetDoState(PointerWrap &p) { netInetInited = cur_netInetInited; g_netInited = cur_netInited; - // Discard leftover events - apctlEvents.clear(); // Discard created resolvers for now (since i'm not sure whether the information in the struct is sufficient or not, and we don't support multi-threading yet anyway) __NetResolverShutdown(); } diff --git a/Core/HLE/sceReg.cpp b/Core/HLE/sceReg.cpp index c43fc4321b..54b0357fa1 100644 --- a/Core/HLE/sceReg.cpp +++ b/Core/HLE/sceReg.cpp @@ -1010,9 +1010,13 @@ static const KeyValue *LookupCategory(std::string_view path, int *count) { } void __RegDoState(PointerWrap &p) { - auto s = p.Section("sceReg", 0, 2); - if (!s) + auto s = p.Section("sceReg", 0, 3); + if (!s) { + if (p.mode == PointerWrap::MODE_READ) { + __RegInit(); + } return; + } Do(p, g_openRegistryMode); Do(p, g_openCategories); if (s >= 2) { @@ -1021,6 +1025,15 @@ void __RegDoState(PointerWrap &p) { // Old states didn't track this. Anything with a category open had the registry open too. g_openRegistryCount = g_openCategories.empty() ? 0 : 1; } + if (s >= 3) { + Do(p, g_handleGen); + } else if (p.mode == PointerWrap::MODE_READ) { + // Don't hand out a handle that's still open in the state. + g_handleGen = 1337; + if (!g_openCategories.empty()) { + g_handleGen = std::max(g_handleGen, g_openCategories.rbegin()->first + 1); + } + } } // Registry level (it seems only /system can exist, so kinda pointless)