From f81250660a9a1ccf51f75318d4aad8fd56821cc2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 24 Jan 2021 11:49:25 -0800 Subject: [PATCH 1/3] Umd: Delay common wait drive stat funcs. These are sometimes used in loading or loops, and take time. This should reduce spin looping. --- Core/HLE/sceUmd.cpp | 53 ++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 51c44b72ae..4d4aba33ce 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -378,22 +378,18 @@ static void __UmdWaitStat(u32 timeout) * @return < 0 on error * */ -static int sceUmdWaitDriveStat(u32 stat) -{ +static int sceUmdWaitDriveStat(u32 stat) { if (stat == 0) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStat(stat = %08x): bad status", stat); - return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; + return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); } - if (!__KernelIsDispatchEnabled()) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStat(stat = %08x): dispatch disabled", stat); - return SCE_KERNEL_ERROR_CAN_NOT_WAIT; + return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } if (__IsInInterrupt()) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStat(stat = %08x): inside interrupt", stat); - return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; + return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "inside interrupt"); } + hleEatCycles(520); if ((stat & __KernelUmdGetState()) == 0) { DEBUG_LOG(SCEIO, "sceUmdWaitDriveStat(stat = %08x): waiting", stat); umdWaitingThreads.push_back(__KernelGetCurThread()); @@ -401,26 +397,21 @@ static int sceUmdWaitDriveStat(u32 stat) return 0; } - DEBUG_LOG(SCEIO, "0=sceUmdWaitDriveStat(stat = %08x)", stat); - return 0; + return hleLogSuccessI(SCEIO, 0); } -static int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) -{ +static int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) { if (stat == 0) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d): bad status", stat, timeout); - return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; + return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); } - if (!__KernelIsDispatchEnabled()) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d): dispatch disabled", stat, timeout); - return SCE_KERNEL_ERROR_CAN_NOT_WAIT; + return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } if (__IsInInterrupt()) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d): inside interrupt", stat, timeout); - return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; + return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "inside interrupt"); } + hleEatCycles(520); if ((stat & __KernelUmdGetState()) == 0) { DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d): waiting", stat, timeout); __UmdWaitStat(timeout); @@ -431,34 +422,29 @@ static int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) hleReSchedule("umd stat checked"); } - DEBUG_LOG(SCEIO, "0=sceUmdWaitDriveStatWithTimer(stat = %08x, timeout = %d)", stat, timeout); - return 0; + return hleLogSuccessI(SCEIO, 0); } -static int sceUmdWaitDriveStatCB(u32 stat, u32 timeout) -{ +static int sceUmdWaitDriveStatCB(u32 stat, u32 timeout) { if (!UMDInserted) { WARN_LOG(SCEIO, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): UMD is taking out for switch UMD", stat, timeout); return PSP_UMD_NOT_PRESENT; } if (stat == 0) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): bad status", stat, timeout); - return SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT; + return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); } - if (!__KernelIsDispatchEnabled()) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): dispatch disabled", stat, timeout); - return SCE_KERNEL_ERROR_CAN_NOT_WAIT; + return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled"); } if (__IsInInterrupt()) { - DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): inside interrupt", stat, timeout); - return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; + return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ILLEGAL_CONTEXT, "inside interrupt"); } + hleEatCycles(520); hleCheckCurrentCallbacks(); if ((stat & __KernelUmdGetState()) == 0) { - DEBUG_LOG(SCEIO, "0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): waiting", stat, timeout); + DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): waiting", stat, timeout); if (timeout == 0) { timeout = 8000; } @@ -470,8 +456,7 @@ static int sceUmdWaitDriveStatCB(u32 stat, u32 timeout) hleReSchedule("umd stat waited"); } - DEBUG_LOG(SCEIO, "0=sceUmdWaitDriveStatCB(stat = %08x, timeout = %d)", stat, timeout); - return 0; + return hleLogSuccessI(SCEIO, 0); } static u32 sceUmdCancelWaitDriveStat() From 871a0f94922cb35aea62e85bb13ba37fa339a6cd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 24 Jan 2021 12:11:42 -0800 Subject: [PATCH 2/3] Umd: Wake waiting threads on eject/insert. --- Core/HLE/sceUmd.cpp | 71 +++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 4d4aba33ce..3b9d743e42 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -42,7 +42,7 @@ const u64 MICRO_DELAY_ACTIVATE = 4000; -static u8 umdActivated = 1; +static bool umdActivated = true; static u32 umdStatus = 0; static u32 umdErrorStat = 0; static int driveCBId = 0; @@ -71,7 +71,7 @@ void __UmdInit() umdStatTimeoutEvent = CoreTiming::RegisterEvent("UmdTimeout", __UmdStatTimeout); umdStatChangeEvent = CoreTiming::RegisterEvent("UmdChange", __UmdStatChange); umdInsertChangeEvent = CoreTiming::RegisterEvent("UmdInsertChange", __UmdInsertChange); - umdActivated = 1; + umdActivated = true; umdStatus = 0; umdErrorStat = 0; driveCBId = 0; @@ -87,7 +87,9 @@ void __UmdDoState(PointerWrap &p) if (!s) return; + u8 activatedByte = umdActivated ? 1 : 0; Do(p, umdActivated); + umdActivated = activatedByte != 0; Do(p, umdStatus); Do(p, umdErrorStat); Do(p, driveCBId); @@ -112,8 +114,11 @@ void __UmdDoState(PointerWrap &p) UMDInserted = true; } -static u8 __KernelUmdGetState() -{ +static u8 __KernelUmdGetState() { + if (!UMDInserted) { + return PSP_UMD_NOT_PRESENT; + } + // Most games seem to expect the disc to be ready early on, active or not. // It seems like the PSP sets this state when the disc is "ready". u8 state = PSP_UMD_PRESENT | PSP_UMD_READY; @@ -123,16 +128,7 @@ static u8 __KernelUmdGetState() return state; } -void __UmdInsertChange(u64 userdata, int cyclesLate) -{ - UMDInserted = true; -} - -void __UmdStatChange(u64 userdata, int cyclesLate) -{ - // TODO: Why not a bool anyway? - umdActivated = userdata & 0xFF; - +static void UmdWakeThreads() { // Wake anyone waiting on this. for (size_t i = 0; i < umdWaitingThreads.size(); ++i) { const SceUID threadID = umdWaitingThreads[i]; @@ -140,19 +136,32 @@ void __UmdStatChange(u64 userdata, int cyclesLate) u32 error; u32 stat = __KernelGetWaitValue(threadID, error); bool keep = false; - if (HLEKernel::VerifyWait(threadID, WAITTYPE_UMD, 1)) { - if ((stat & __KernelUmdGetState()) != 0) - __KernelResumeThreadFromWait(threadID, 0); + if (!HLEKernel::VerifyWait(threadID, WAITTYPE_UMD, 1)) { // Only if they are still waiting do we keep them in the list. - else - keep = true; + keep = (stat & __KernelUmdGetState()) == 0; + if (!keep) { + __KernelResumeThreadFromWait(threadID, 0); + } } - if (!keep) + if (!keep) { umdWaitingThreads.erase(umdWaitingThreads.begin() + i--); + } } } +static void __UmdStatChange(u64 userdata, int cyclesLate) { + umdActivated = userdata != 0; + + UmdWakeThreads(); +} + +static void __UmdInsertChange(u64 userdata, int cyclesLate) { + UMDInserted = true; + + UmdWakeThreads(); +} + static void __KernelUmdActivate() { u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE; @@ -268,20 +277,16 @@ static u32 sceUmdGetDiscInfo(u32 infoAddr) return PSP_ERROR_UMD_INVALID_PARAM; } -static int sceUmdActivate(u32 mode, const char *name) -{ +static int sceUmdActivate(u32 mode, const char *name) { if (mode < 1 || mode > 2) - return PSP_ERROR_UMD_INVALID_PARAM; + return hleLogWarning(SCEIO, PSP_ERROR_UMD_INVALID_PARAM); __KernelUmdActivate(); - if (mode == 1) { - DEBUG_LOG(SCEIO, "0=sceUmdActivate(%d, %s)", mode, name); - } else { - ERROR_LOG(SCEIO, "UNTESTED 0=sceUmdActivate(%d, %s)", mode, name); + if (mode != 1) { + return hleLogError(SCEIO, 0, "UNTESTED"); } - - return 0; + return hleLogSuccessI(SCEIO, 0); } static int sceUmdDeactivate(u32 mode, const char *name) @@ -426,11 +431,6 @@ static int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) { } static int sceUmdWaitDriveStatCB(u32 stat, u32 timeout) { - if (!UMDInserted) { - WARN_LOG(SCEIO, "sceUmdWaitDriveStatCB(stat = %08x, timeout = %d): UMD is taking out for switch UMD", stat, timeout); - return PSP_UMD_NOT_PRESENT; - } - if (stat == 0) { return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); } @@ -487,6 +487,9 @@ void __UmdReplace(std::string filepath) { } UMDInserted = false; + // Wake any threads waiting for the disc to be removed. + UmdWakeThreads(); + CoreTiming::ScheduleEvent(usToCycles(200*1000), umdInsertChangeEvent, 0); // Wait sceUmdCheckMedium call // TODO Is this always correct if UMD was not activated? u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE | PSP_UMD_CHANGED; From cfb52bf69edabe3e0624a62f2dbe4d9715bc9969 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 24 Jan 2021 12:20:52 -0800 Subject: [PATCH 3/3] Umd: Disallow waiting on status that can't occur. Per tests, CHANGED is not waitable. --- Core/HLE/sceUmd.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 3b9d743e42..1b666ddb21 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -40,7 +40,9 @@ #include "Core/FileSystems/ISOFileSystem.h" #include "Core/FileSystems/VirtualDiscFileSystem.h" -const u64 MICRO_DELAY_ACTIVATE = 4000; +static constexpr u64 MICRO_DELAY_ACTIVATE = 4000; +// Does not include PSP_UMD_CHANGED. +static constexpr uint32_t UMD_STAT_ALLOW_WAIT = PSP_UMD_NOT_PRESENT | PSP_UMD_PRESENT | PSP_UMD_NOT_READY | PSP_UMD_READY | PSP_UMD_READABLE; static bool umdActivated = true; static u32 umdStatus = 0; @@ -60,11 +62,11 @@ struct PspUmdInfo { u32_le type; }; -void __UmdStatTimeout(u64 userdata, int cyclesLate); -void __UmdStatChange(u64 userdata, int cyclesLate); -void __UmdInsertChange(u64 userdata, int cyclesLate); -void __UmdBeginCallback(SceUID threadID, SceUID prevCallbackId); -void __UmdEndCallback(SceUID threadID, SceUID prevCallbackId); +static void __UmdStatTimeout(u64 userdata, int cyclesLate); +static void __UmdStatChange(u64 userdata, int cyclesLate); +static void __UmdInsertChange(u64 userdata, int cyclesLate); +static void __UmdBeginCallback(SceUID threadID, SceUID prevCallbackId); +static void __UmdEndCallback(SceUID threadID, SceUID prevCallbackId); void __UmdInit() { @@ -187,7 +189,7 @@ static void __KernelUmdDeactivate() __UmdStatChange(0, 0); } -void __UmdBeginCallback(SceUID threadID, SceUID prevCallbackId) +static void __UmdBeginCallback(SceUID threadID, SceUID prevCallbackId) { SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; @@ -213,7 +215,7 @@ void __UmdBeginCallback(SceUID threadID, SceUID prevCallbackId) WARN_LOG_REPORT(SCEIO, "sceUmdWaitDriveStatCB: beginning callback with bad wait id?"); } -void __UmdEndCallback(SceUID threadID, SceUID prevCallbackId) +static void __UmdEndCallback(SceUID threadID, SceUID prevCallbackId) { SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId; @@ -352,7 +354,7 @@ static u32 sceUmdGetDriveStat() return retVal; } -void __UmdStatTimeout(u64 userdata, int cyclesLate) +static void __UmdStatTimeout(u64 userdata, int cyclesLate) { SceUID threadID = (SceUID)userdata; @@ -384,7 +386,7 @@ static void __UmdWaitStat(u32 timeout) * */ static int sceUmdWaitDriveStat(u32 stat) { - if (stat == 0) { + if ((stat & UMD_STAT_ALLOW_WAIT) == 0) { return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); } if (!__KernelIsDispatchEnabled()) { @@ -406,7 +408,7 @@ static int sceUmdWaitDriveStat(u32 stat) { } static int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) { - if (stat == 0) { + if ((stat & UMD_STAT_ALLOW_WAIT) == 0) { return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); } if (!__KernelIsDispatchEnabled()) { @@ -431,7 +433,7 @@ static int sceUmdWaitDriveStatWithTimer(u32 stat, u32 timeout) { } static int sceUmdWaitDriveStatCB(u32 stat, u32 timeout) { - if (stat == 0) { + if ((stat & UMD_STAT_ALLOW_WAIT) == 0) { return hleLogDebug(SCEIO, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "bad status"); } if (!__KernelIsDispatchEnabled()) {