Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement volatile memory lock waits #3412

Merged
merged 2 commits into from
Aug 26, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Core/HLE/sceKernelThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const WaitTypeNames waitTypeNames[] = {
{ WAITTYPE_MODULE, "Module" },
{ WAITTYPE_HLEDELAY, "HleDelay" },
{ WAITTYPE_TLS, "TLS" },
{ WAITTYPE_VMEM, "Volatile Mem" },
};

const char *getWaitTypeName(WaitType type)
Expand Down
3 changes: 2 additions & 1 deletion Core/HLE/sceKernelThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ struct SceKernelSysClock {
};


// TODO: Map these to PSP wait types.
// TODO: Map these to PSP wait types. Most of these are wrong.
// remember to update the waitTypeNames array in sceKernelThread.cpp when changing these
enum WaitType
{
Expand All @@ -93,6 +93,7 @@ enum WaitType
WAITTYPE_MODULE = 19,
WAITTYPE_HLEDELAY = 20,
WAITTYPE_TLS = 21,
WAITTYPE_VMEM = 22,

NUM_WAITTYPES
};
Expand Down
121 changes: 94 additions & 27 deletions Core/HLE/scePower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <map>
#include <vector>
#include "Common/ChunkFile.h"
#include "Core/HLE/HLE.h"
#include "Core/CoreTiming.h"
Expand All @@ -24,6 +25,12 @@
#include "Core/HLE/scePower.h"
#include "Core/HLE/sceKernelThread.h"

struct VolatileWaitingThread {
SceUID threadID;
u32 addrPtr;
u32 sizePtr;
};

const int PSP_POWER_ERROR_TAKEN_SLOT = 0x80000020;
const int PSP_POWER_ERROR_SLOTS_FULL = 0x80000022;
const int PSP_POWER_ERROR_PRIVATE_SLOT = 0x80000023;
Expand All @@ -45,6 +52,7 @@ const int numberOfCBPowerSlotsPrivate = 32;

static bool volatileMemLocked;
static int powerCbSlots[numberOfCBPowerSlots];
static std::vector<VolatileWaitingThread> volatileWaitingThreads;

// this should belong here on in CoreTiming?
static int pllFreq = 222;
Expand All @@ -53,6 +61,7 @@ static int busFreq = 111;
void __PowerInit() {
memset(powerCbSlots, 0, sizeof(powerCbSlots));
volatileMemLocked = false;
volatileWaitingThreads.clear();

if(g_Config.iLockedCPUSpeed > 0) {
CoreTiming::SetClockFrequencyMHz(g_Config.iLockedCPUSpeed);
Expand All @@ -64,6 +73,7 @@ void __PowerInit() {
void __PowerDoState(PointerWrap &p) {
p.DoArray(powerCbSlots, ARRAY_SIZE(powerCbSlots));
p.Do(volatileMemLocked);
p.Do(volatileWaitingThreads);
p.DoMarker("scePower");
}

Expand Down Expand Up @@ -199,12 +209,11 @@ int sceKernelPowerTick(int flag) {

#define ERROR_POWER_VMEM_IN_USE 0x802b0200

int sceKernelVolatileMemTryLock(int type, int paddr, int psize) {
if (!volatileMemLocked) {
INFO_LOG(HLE,"sceKernelVolatileMemTryLock(%i, %08x, %i) - success", type, paddr, psize);
volatileMemLocked = true;
} else {
ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %i) - already locked!", type, paddr, psize);
int __KernelVolatileMemLock(int type, u32 paddr, u32 psize) {
if (type != 0) {
return SCE_KERNEL_ERROR_INVALID_MODE;
}
if (volatileMemLocked) {
return ERROR_POWER_VMEM_IN_USE;
}

Expand All @@ -213,22 +222,89 @@ int sceKernelVolatileMemTryLock(int type, int paddr, int psize) {
// TODO: Should really reserve this properly!
Memory::Write_U32(0x08400000, paddr);
Memory::Write_U32(0x00400000, psize);
volatileMemLocked = true;

return 0;
}

int sceKernelVolatileMemTryLock(int type, u32 paddr, u32 psize) {
int error = __KernelVolatileMemLock(type, paddr, psize);

switch (error) {
case 0:
INFO_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - success", type, paddr, psize);
break;

case ERROR_POWER_VMEM_IN_USE:
ERROR_LOG(HLE, "sceKernelVolatileMemTryLock(%i, %08x, %08x) - already locked!", type, paddr, psize);
break;

default:
ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemTryLock(%i, %08x, %08x) - error", type, paddr, psize, error);
break;
}

return error;
}

int sceKernelVolatileMemUnlock(int type) {
if (type != 0) {
ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemUnlock(%i) - invalid mode", type);
return SCE_KERNEL_ERROR_INVALID_MODE;
}
if (volatileMemLocked) {
INFO_LOG(HLE,"sceKernelVolatileMemUnlock(%i)", type);
volatileMemLocked = false;

// Wake someone, always fifo.
bool wokeThreads = false;
u32 error;
while (!volatileWaitingThreads.empty() && !volatileMemLocked) {
VolatileWaitingThread waitInfo = volatileWaitingThreads.front();
volatileWaitingThreads.erase(volatileWaitingThreads.begin());

int waitID = __KernelGetWaitID(waitInfo.threadID, WAITTYPE_VMEM, error);
// If they were force-released, just skip.
if (waitID == 1 && __KernelVolatileMemLock(0, waitInfo.addrPtr, waitInfo.sizePtr) == 0) {
__KernelResumeThreadFromWait(waitInfo.threadID, 0);
wokeThreads = true;
}
}

if (wokeThreads) {
INFO_LOG(HLE, "sceKernelVolatileMemUnlock(%i) handed over to another thread", type);
hleReSchedule("volatile mem unlocked");
} else {
INFO_LOG(HLE, "sceKernelVolatileMemUnlock(%i)", type);
}
} else {
ERROR_LOG_REPORT(HLE, "sceKernelVolatileMemUnlock(%i) FAILED - not locked", type);
}
return 0;
}

int sceKernelVolatileMemLock(int type, int paddr, int psize) {
return sceKernelVolatileMemTryLock(type, paddr, psize);
int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) {
int error = __KernelVolatileMemLock(type, paddr, psize);

switch (error) {
case 0:
INFO_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - success", type, paddr, psize);
break;

case ERROR_POWER_VMEM_IN_USE:
{
WARN_LOG(HLE, "sceKernelVolatileMemLock(%i, %08x, %08x) - already locked, waiting", type, paddr, psize);
const VolatileWaitingThread waitInfo = { __KernelGetCurThread(), paddr, psize };
volatileWaitingThreads.push_back(waitInfo);
__KernelWaitCurThread(WAITTYPE_VMEM, 1, 0, 0, false, "volatile mem waited");
}
break;

default:
ERROR_LOG_REPORT(HLE, "%08x=sceKernelVolatileMemLock(%i, %08x, %08x) - error", type, paddr, psize, error);
break;
}

return error;
}


Expand Down Expand Up @@ -267,17 +343,6 @@ u32 scePowerSetBusClockFrequency(u32 busfreq) {
return 0;
}

u32 scePowerGetCpuClockFrequency() {
int cpuFreq = CoreTiming::GetClockFrequencyMHz();
DEBUG_LOG(HLE,"%i=scePowerGetCpuClockFrequency()", cpuFreq);
return cpuFreq;
}

u32 scePowerGetBusClockFrequency() {
INFO_LOG(HLE,"%i=scePowerGetBusClockFrequency()", busFreq);
return busFreq;
}

u32 scePowerGetCpuClockFrequencyInt() {
int cpuFreq = CoreTiming::GetClockFrequencyMHz();
DEBUG_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", cpuFreq);
Expand Down Expand Up @@ -361,8 +426,8 @@ static const HLEFunction scePower[] = {
{0xDB9D28DD,WrapI_I<scePowerUnregisterCallback>,"scePowerUnregitserCallback"},
{0x843FBF43,WrapU_U<scePowerSetCpuClockFrequency>,"scePowerSetCpuClockFrequency"},
{0xB8D7B3FB,WrapU_U<scePowerSetBusClockFrequency>,"scePowerSetBusClockFrequency"},
{0xFEE03A2F,WrapU_V<scePowerGetCpuClockFrequency>,"scePowerGetCpuClockFrequency"},
{0x478FE6F5,WrapU_V<scePowerGetBusClockFrequency>,"scePowerGetBusClockFrequency"},
{0xFEE03A2F,WrapU_V<scePowerGetCpuClockFrequencyInt>,"scePowerGetCpuClockFrequency"},
{0x478FE6F5,WrapU_V<scePowerGetBusClockFrequencyInt>,"scePowerGetBusClockFrequency"},
{0xFDB5BFE9,WrapU_V<scePowerGetCpuClockFrequencyInt>,"scePowerGetCpuClockFrequencyInt"},
{0xBD681969,WrapU_V<scePowerGetBusClockFrequencyInt>,"scePowerGetBusClockFrequencyInt"},
{0xB1A52C83,WrapF_V<scePowerGetCpuClockFrequencyFloat>,"scePowerGetCpuClockFrequencyFloat"},
Expand All @@ -379,9 +444,11 @@ static const HLEFunction scePower[] = {
{0x0442d852,0,"scePowerRequestColdReset"},
{0xbafa3df0,0,"scePowerGetCallbackMode"},
{0xa9d22232,0,"scePowerSetCallbackMode"},
{0x23c31ffe,0,"scePowerVolatileMemLock"},
{0xfa97a599,0,"scePowerVolatileMemTryLock"},
{0xb3edd801,0,"scePowerVolatileMemUnlock"},

// These seem to be aliases.
{0x23c31ffe,&WrapI_IUU<sceKernelVolatileMemLock>,"scePowerVolatileMemLock"},
{0xfa97a599,&WrapI_IUU<sceKernelVolatileMemTryLock>,"scePowerVolatileMemTryLock"},
{0xb3edd801,&WrapI_I<sceKernelVolatileMemUnlock>,"scePowerVolatileMemUnlock"},
};

//890129c in tyshooter looks bogus
Expand All @@ -392,9 +459,9 @@ const HLEFunction sceSuspendForUser[] = {

// There's an extra 4MB that can be allocated, which seems to be "volatile". These functions
// let you grab it.
{0xa14f40b2,&WrapI_III<sceKernelVolatileMemTryLock>,"sceKernelVolatileMemTryLock"},
{0xa14f40b2,&WrapI_IUU<sceKernelVolatileMemTryLock>,"sceKernelVolatileMemTryLock"},
{0xa569e425,&WrapI_I<sceKernelVolatileMemUnlock>,"sceKernelVolatileMemUnlock"},
{0x3e0271d3,&WrapI_III<sceKernelVolatileMemLock>,"sceKernelVolatileMemLock"}, //when "acquiring mem pool" (fired up)
{0x3e0271d3,&WrapI_IUU<sceKernelVolatileMemLock>,"sceKernelVolatileMemLock"}, //when "acquiring mem pool" (fired up)
};


Expand Down