From d13f76308d7a43c1f5d1055d895c6d531fe4ec96 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 25 Aug 2018 10:32:32 -0700 Subject: [PATCH 1/2] Ge: Avoid executing invalid pointers. May help #3407 and related errors, as well as crashes and execution of garbage. This stops immediately on a bad pointer, rather than trying to push through. --- Core/HLE/sceGe.cpp | 6 +++--- GPU/GPUCommon.cpp | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index fad468bfa8..dafa5d09b1 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -353,10 +353,10 @@ u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, int callbackId, u32 auto optParam = PSPPointer::Create(optParamAddr); u32 listID = gpu->EnqueueList(listAddress, stallAddress, __GeSubIntrBase(callbackId), optParam, true); - if ((int)listID >= 0) + if ((int)listID >= 0) { listID = LIST_ID_MAGIC ^ listID; - - DEBUG_LOG(SCEGE, "List %i enqueued at head.", listID); + DEBUG_LOG(SCEGE, "List %i enqueued at head.", listID); + } hleEatCycles(480); CoreTiming::ForceCheck(); return listID; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 6339504d0d..77a2548291 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -632,8 +632,10 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointerpc, target - 4); currentList->pc = target - 4; // pc will be increased after we return, counteract that } @@ -1184,6 +1185,7 @@ void GPUCommon::Execute_BJump(u32 op, u32 diff) { currentList->pc = target - 4; // pc will be increased after we return, counteract that } else { ERROR_LOG_REPORT(G3D, "BJUMP to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + UpdateState(GPUSTATE_ERROR); } } } @@ -1194,12 +1196,11 @@ void GPUCommon::Execute_Call(u32 op, u32 diff) { // Saint Seiya needs correct support for relative calls. const u32 retval = currentList->pc + 4; const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); -#ifdef _DEBUG if (!Memory::IsValidAddress(target)) { ERROR_LOG_REPORT(G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); + UpdateState(GPUSTATE_ERROR); return; } -#endif // Bone matrix optimization - many games will CALL a bone matrix (!). // We don't optimize during recording - so the matrix data gets recorded. @@ -1304,6 +1305,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { u32 target = (((signal << 16) | enddata) & 0xFFFFFFFC) - 4; if (!Memory::IsValidAddress(target)) { ERROR_LOG_REPORT(G3D, "Signal with Jump: bad address. signal/end: %04x %04x", signal, enddata); + UpdateState(GPUSTATE_ERROR); } else { UpdatePC(currentList->pc, target); currentList->pc = target; @@ -1321,6 +1323,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) { ERROR_LOG_REPORT(G3D, "Signal with Call: stack full. signal/end: %04x %04x", signal, enddata); } else if (!Memory::IsValidAddress(target)) { ERROR_LOG_REPORT(G3D, "Signal with Call: bad address. signal/end: %04x %04x", signal, enddata); + UpdateState(GPUSTATE_ERROR); } else { // TODO: This might save/restore other state... auto &stackEntry = currentList->stack[currentList->stackptr++]; From 6ee0612a105803b208d22d920d8685d50cb5ac4e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 25 Aug 2018 10:38:56 -0700 Subject: [PATCH 2/2] Ge: Keep jump/call optim when fast memory on. This gives a way to validate with fast memory off, and get less crashes. --- GPU/GPUCommon.cpp | 29 +++++++++++++++++++++++++++-- GPU/GPUCommon.h | 3 +++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 77a2548291..69d733835b 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -420,6 +420,14 @@ void GPUCommon::UpdateCmdInfo() { cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE; cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType; } + + if (g_Config.bFastMemory) { + cmdInfo_[GE_CMD_JUMP].func = &GPUCommon::Execute_JumpFast; + cmdInfo_[GE_CMD_CALL].func = &GPUCommon::Execute_CallFast; + } else { + cmdInfo_[GE_CMD_JUMP].func = &GPUCommon::Execute_Jump; + cmdInfo_[GE_CMD_CALL].func = &GPUCommon::Execute_Call; + } } void GPUCommon::BeginHostFrame() { @@ -1176,6 +1184,12 @@ void GPUCommon::Execute_Jump(u32 op, u32 diff) { currentList->pc = target - 4; // pc will be increased after we return, counteract that } +void GPUCommon::Execute_JumpFast(u32 op, u32 diff) { + const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); + UpdatePC(currentList->pc, target - 4); + currentList->pc = target - 4; // pc will be increased after we return, counteract that +} + void GPUCommon::Execute_BJump(u32 op, u32 diff) { if (!currentList->bboxResult) { // bounding box jump. @@ -1193,14 +1207,25 @@ void GPUCommon::Execute_BJump(u32 op, u32 diff) { void GPUCommon::Execute_Call(u32 op, u32 diff) { PROFILE_THIS_SCOPE("gpu_call"); - // Saint Seiya needs correct support for relative calls. - const u32 retval = currentList->pc + 4; const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); if (!Memory::IsValidAddress(target)) { ERROR_LOG_REPORT(G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, op & 0x00FFFFFF); UpdateState(GPUSTATE_ERROR); return; } + DoExecuteCall(target); +} + +void GPUCommon::Execute_CallFast(u32 op, u32 diff) { + PROFILE_THIS_SCOPE("gpu_call"); + + const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC); + DoExecuteCall(target); +} + +void GPUCommon::DoExecuteCall(u32 target) { + // Saint Seiya needs correct support for relative calls. + const u32 retval = currentList->pc + 4; // Bone matrix optimization - many games will CALL a bone matrix (!). // We don't optimize during recording - so the matrix data gets recorded. diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 36442d50de..63f6661594 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -125,8 +125,10 @@ public: void Execute_Iaddr(u32 op, u32 diff); void Execute_Origin(u32 op, u32 diff); void Execute_Jump(u32 op, u32 diff); + void Execute_JumpFast(u32 op, u32 diff); void Execute_BJump(u32 op, u32 diff); void Execute_Call(u32 op, u32 diff); + void Execute_CallFast(u32 op, u32 diff); void Execute_Ret(u32 op, u32 diff); void Execute_End(u32 op, u32 diff); @@ -287,6 +289,7 @@ protected: virtual void FinishDeferred() {} void DoBlockTransfer(u32 skipDrawReason); + void DoExecuteCall(u32 target); void AdvanceVerts(u32 vertType, int count, int bytesRead) { if ((vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {