diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 60811a7c47..538c811a43 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -736,6 +736,11 @@ void UtilityDialogShutdown(UtilityDialogType type, int delayUs, int accessPriori // The windows aren't this regular, but close. int partDelay = delayUs / 4; const int dialogPriority = PhasePriority(graphicsPriority, accessPriority); + // A savedata shutdown ends at priority 0x20, whatever the dialog's thread priorities: a caller at + // 0x20 gets the CPU back first and sees SHUTDOWN, one at 0x21 or worse only NONE + // (pspautotests utility/savedata/shutdownstatus). Freak Out calls ShutdownStart from 0x20 and + // waits for SHUTDOWN; NFL Street 3 calls it from 111 and then InitStart straight away. + const int finalPriority = type == UtilityDialogType::SAVEDATA ? 0x20 : accessPriority; const u32_le insts[] = { // Make sure we don't discard/deadbeef 'em. (u32_le)MIPS_MAKE_ORI(MIPS_REG_S0, MIPS_REG_A0, 0), @@ -749,7 +754,7 @@ void UtilityDialogShutdown(UtilityDialogType type, int delayUs, int accessPriori (u32_le)MIPS_MAKE_ORI(MIPS_REG_A0, MIPS_REG_S0, 0), (u32_le)MIPS_MAKE_SYSCALL("sceUtility", "__UtilityWorkUs"), - // Cleaning up at accessThread priority, then the status goes to NONE. + // Cleaning up at accessThread priority. (u32_le)MIPS_MAKE_ORI(MIPS_REG_A0, MIPS_REG_ZERO, 0), (u32_le)MIPS_MAKE_ORI(MIPS_REG_A1, MIPS_REG_ZERO, accessPriority), (u32_le)MIPS_MAKE_SYSCALL("ThreadManForUser", "sceKernelChangeThreadPriority"), @@ -758,13 +763,18 @@ void UtilityDialogShutdown(UtilityDialogType type, int delayUs, int accessPriori (u32_le)MIPS_MAKE_ORI(MIPS_REG_A0, MIPS_REG_S0, 0), (u32_le)MIPS_MAKE_SYSCALL("sceUtility", "__UtilityWorkUs"), + // Then the status goes to NONE, from priority finalPriority (see below). + (u32_le)MIPS_MAKE_ORI(MIPS_REG_A0, MIPS_REG_ZERO, 0), + (u32_le)MIPS_MAKE_ORI(MIPS_REG_A1, MIPS_REG_ZERO, finalPriority), + (u32_le)MIPS_MAKE_SYSCALL("ThreadManForUser", "sceKernelChangeThreadPriority"), + (u32_le)MIPS_MAKE_ORI(MIPS_REG_A0, MIPS_REG_ZERO, (int)type), (u32_le)MIPS_MAKE_JR_RA(), (u32_le)MIPS_MAKE_SYSCALL("sceUtility", "__UtilityFinishDialog"), }; - // Starting the thread reschedules normally, so a caller with worse priority than both phases sees - // NONE by the time ShutdownStart returns. + // Starting the thread reschedules normally, so a caller with worse priority than every phase + // only runs again once the status is NONE. CleanupDialogThreads(true); accessThread = new HLEHelperThread("ScePafJob", insts, (uint32_t)ARRAY_SIZE(insts), accessPriority, 0x200); accessThread->Start(partDelay, 0);