Merge pull request #1286 from unknownbrackets/tls-object

Basic support for the new TLS object functions
This commit is contained in:
Henrik Rydgård 2013-04-15 01:22:48 -07:00
commit e1b1e6af85
5 changed files with 293 additions and 18 deletions

View File

@ -538,6 +538,8 @@ KernelObject *KernelObjectPool::CreateByIDType(int type)
return __KernelThreadObject();
case SCE_KERNEL_TMID_VTimer:
return __KernelVTimerObject();
case SCE_KERNEL_TMID_Tls:
return __KernelTlsObject();
case PPSSPP_KERNEL_TMID_File:
return __KernelFileNodeObject();
case PPSSPP_KERNEL_TMID_DirList:
@ -639,6 +641,11 @@ const HLEFunction ThreadManForUser[] =
{0x19CFF145,&WrapI_UCUIU<sceKernelCreateLwMutex>, "sceKernelCreateLwMutex"},
{0x4C145944,&WrapI_IU<sceKernelReferLwMutexStatusByID>, "sceKernelReferLwMutexStatusByID"},
// NOTE: LockLwMutex, UnlockLwMutex, and ReferLwMutexStatus are in Kernel_Library, see sceKernelInterrupt.cpp.
// The below should not be called directly.
//{0x71040D5C,0, "_sceKernelTryLockLwMutex"},
//{0x7CFF8CF3,0, "_sceKernelLockLwMutex"},
//{0x31327F19,0, "_sceKernelLockLwMutexCB"},
//{0xBEED3A47,0, "_sceKernelUnlockLwMutex"},
{0xf8170fbe,&WrapI_I<sceKernelDeleteMutex>, "sceKernelDeleteMutex"},
{0xB011B11F,&WrapI_IIU<sceKernelLockMutex>, "sceKernelLockMutex", HLE_NOT_DISPATCH_SUSPENDED},
@ -647,8 +654,10 @@ const HLEFunction ThreadManForUser[] =
{0xb7d098c6,&WrapI_CUIU<sceKernelCreateMutex>, "sceKernelCreateMutex"},
{0x0DDCD2C9,&WrapI_II<sceKernelTryLockMutex>, "sceKernelTryLockMutex"},
{0xA9C2CB9A,&WrapI_IU<sceKernelReferMutexStatus>, "sceKernelReferMutexStatus"},
{0x87D9223C,0, "sceKernelCancelMutex"},
{0xFCCFAD26,sceKernelCancelWakeupThread,"sceKernelCancelWakeupThread"},
{0x1AF94D03,0,"sceKernelDonateWakeupThread"},
{0xea748e31,sceKernelChangeCurrentThreadAttr,"sceKernelChangeCurrentThreadAttr"},
{0x71bc9871,sceKernelChangeThreadPriority,"sceKernelChangeThreadPriority"},
{0x446D8DE6,WrapI_CUUIUU<sceKernelCreateThread>,"sceKernelCreateThread"},
@ -682,6 +691,8 @@ const HLEFunction ThreadManForUser[] =
{0x94416130,WrapU_UUUU<sceKernelGetThreadmanIdList>,"sceKernelGetThreadmanIdList"},
{0x57CF62DD,WrapU_U<sceKernelGetThreadmanIdType>,"sceKernelGetThreadmanIdType"},
{0xBC80EC7C,WrapU_UUUU<sceKernelExtendThreadStack>, "sceKernelExtendThreadStack"},
// NOTE: Takes a UID from sceKernelMemory's AllocMemoryBlock and seems thread stack related.
//{0x28BFD974,0,"ThreadManForUser_28BFD974"},
{0x82BC5777,WrapU64_V<sceKernelGetSystemTimeWide>,"sceKernelGetSystemTimeWide"},
{0xdb738f35,WrapI_U<sceKernelGetSystemTime>,"sceKernelGetSystemTime"},
@ -770,8 +781,15 @@ const HLEFunction ThreadManForUser[] =
{0xd8b299ae,WrapU_UUUU<sceKernelSetVTimerHandler>,"sceKernelSetVTimerHandler"},
{0x53B00E9A,WrapU_UU64UU<sceKernelSetVTimerHandlerWide>,"sceKernelSetVTimerHandlerWide"},
{0x8daff657,WrapI_CUUUUU<ThreadManForUser_8DAFF657>,"ThreadManForUser_8DAFF657"},
{0x32bf938e,WrapI_I<ThreadManForUser_32BF938E>,"ThreadManForUser_32BF938E"},
// Names are just guesses, not correct.
{0x8daff657,WrapI_CUUUUU<sceKernelCreateTls>, "sceKernelCreateTls"},
{0x32bf938e,WrapI_I<sceKernelDeleteTls>, "sceKernelDeleteTls"},
{0x721067F3,WrapI_IU<sceKernelReferTlsStatus>, "sceKernelReferTlsStatus"},
// Not completely certain about args.
{0x4A719FB2,WrapI_I<sceKernelFreeTls>, "sceKernelFreeTls"},
// Probably internal, not sure. Takes (uid, &addr) as parameters... probably.
//{0x65F54FFB,0, "_sceKernelAllocateTls"},
// NOTE: sceKernelAllocateTls is in Kernel_Library, see sceKernelInterrupt.cpp.
// Not sure if these should be hooked up. See below.
{0x0E927AED, _sceKernelReturnFromTimerHandler, "_sceKernelReturnFromTimerHandler"},

View File

@ -252,6 +252,8 @@ enum TMIDPurpose
SCE_KERNEL_TMID_DelayThread = 65,
SCE_KERNEL_TMID_SuspendThread = 66,
SCE_KERNEL_TMID_DormantThread = 67,
// No idea what the correct value is here or how to find out.
SCE_KERNEL_TMID_Tls = 0x1001,
// Not official, but need ids for save states.
PPSSPP_KERNEL_TMID_Module = 0x100001,

View File

@ -575,7 +575,8 @@ const HLEFunction Kernel_Library[] =
{0x293b45b8,WrapI_V<sceKernelGetThreadId>, "sceKernelGetThreadId"},
{0xD13BDE95,WrapI_V<sceKernelCheckThreadStack>, "sceKernelCheckThreadStack"},
{0x1839852A,WrapU_UUU<sceKernelMemcpy>, "sce_paf_private_memcpy"},
{0xfa835cde,WrapI_I<Kernel_Library_FA835CDE>, "Kernel_Library_FA835CDE"},
// Name is only a guess.
{0xfa835cde,WrapI_I<sceKernelAllocateTls>, "sceKernelAllocateTls"},
};
void Register_Kernel_Library()

View File

@ -27,6 +27,7 @@
#include "sceKernelThread.h"
#include "sceKernelMemory.h"
const int TLS_NUM_INDEXES = 16;
//////////////////////////////////////////////////////////////////////////
// STATE BEGIN
@ -34,6 +35,7 @@ BlockAllocator userMemory(256);
BlockAllocator kernelMemory(256);
static int vplWaitTimer = -1;
static bool tlsUsedIndexes[TLS_NUM_INDEXES];
// STATE END
//////////////////////////////////////////////////////////////////////////
@ -159,14 +161,24 @@ void __KernelMemoryInit()
INFO_LOG(HLE, "Kernel and user memory pools initialized");
vplWaitTimer = CoreTiming::RegisterEvent("VplTimeout", __KernelVplTimeout);
flags_ = 0;
sdkVersion_ = 0;
compilerVersion_ = 0;
memset(tlsUsedIndexes, 0, sizeof(tlsUsedIndexes));
}
void __KernelMemoryDoState(PointerWrap &p)
{
kernelMemory.DoState(p);
userMemory.DoState(p);
p.Do(vplWaitTimer);
CoreTiming::RestoreRegisterEvent(vplWaitTimer, "VplTimeout", __KernelVplTimeout);
p.Do(flags_);
p.Do(sdkVersion_);
p.Do(compilerVersion_);
p.DoArray(tlsUsedIndexes, ARRAY_SIZE(tlsUsedIndexes));
p.DoMarker("sceKernelMemory");
}
@ -1175,26 +1187,265 @@ u32 GetMemoryBlockPtr(u32 uid, u32 addr) {
// These aren't really in sysmem, but they are memory related?
SceUID ThreadManForUser_8DAFF657(const char *name, u32 partitionid, u32 attr, u32 size, u32 count, u32 optionsPtr)
enum
{
u32 totalSize = size * count;
u32 blockPtr = userMemory.Alloc(totalSize, (attr & 0x4000) != 0, name);
PSP_ERROR_UNKNOWN_TLS_ID = 0x800201D0,
PSP_ERROR_TOO_MANY_TLS = 0x800201D1,
};
enum
{
// TODO: Complete untested guesses.
PSP_TLS_ATTR_FIFO = 0,
PSP_TLS_ATTR_PRIORITY = 0x100,
PSP_TLS_ATTR_HIGHMEM = 0x4000,
PSP_TLS_ATTR_KNOWN = PSP_TLS_ATTR_HIGHMEM | PSP_TLS_ATTR_PRIORITY | PSP_TLS_ATTR_FIFO,
};
struct NativeTls
{
SceSize size;
char name[32];
SceUInt attr;
int index;
u32 blockSize;
u32 totalBlocks;
u32 freeBlocks;
u32 numWaitThreads;
};
struct TLS : public KernelObject
{
const char *GetName() {return ntls.name;}
const char *GetTypeName() {return "TLS";}
static u32 GetMissingErrorCode() { return PSP_ERROR_UNKNOWN_TLS_ID; }
int GetIDType() const { return SCE_KERNEL_TMID_Vpl; }
TLS() : next(0) {}
virtual void DoState(PointerWrap &p)
{
p.Do(ntls);
p.Do(address);
p.Do(next);
p.Do(usage);
p.DoMarker("TLS");
}
NativeTls ntls;
u32 address;
// TODO: Waiting threads.
int next;
std::vector<SceUID> usage;
};
KernelObject *__KernelTlsObject()
{
return new TLS;
}
SceUID sceKernelCreateTls(const char *name, u32 partition, u32 attr, u32 blockSize, u32 count, u32 optionsPtr)
{
if (!name)
{
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateTls(): invalid name", SCE_KERNEL_ERROR_NO_MEMORY);
return SCE_KERNEL_ERROR_NO_MEMORY;
}
if ((attr & ~PSP_TLS_ATTR_KNOWN) >= 0x100)
{
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateTls(): invalid attr parameter: %08x", SCE_KERNEL_ERROR_ILLEGAL_ATTR, attr);
return SCE_KERNEL_ERROR_ILLEGAL_ATTR;
}
if (partition < 1 || partition > 9 || partition == 7)
{
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateTls(): invalid partition %d", SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, partition);
return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT;
}
// We only support user right now.
if (partition != 2 && partition != 6)
{
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateTls(): invalid partition %d", SCE_KERNEL_ERROR_ILLEGAL_PERM, partition);
return SCE_KERNEL_ERROR_ILLEGAL_PERM;
}
// There's probably a simpler way to get this same basic formula...
// This is based on results from a PSP.
bool illegalMemSize = blockSize == 0 || count == 0;
if (!illegalMemSize && (u64) blockSize > ((0x100000000ULL / (u64) count) - 4ULL))
illegalMemSize = true;
if (!illegalMemSize && (u64) count >= 0x100000000ULL / (((u64) blockSize + 3ULL) & ~3ULL))
illegalMemSize = true;
if (illegalMemSize)
{
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateTls(): invalid blockSize/count", SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE);
return SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE;
}
int index = -1;
for (int i = 0; i < TLS_NUM_INDEXES; ++i)
if (tlsUsedIndexes[i] == false)
{
index = i;
break;
}
if (index == -1)
{
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateTls(): ran out of indexes for TLS objects", PSP_ERROR_TOO_MANY_TLS);
return PSP_ERROR_TOO_MANY_TLS;
}
u32 totalSize = blockSize * count;
u32 blockPtr = userMemory.Alloc(totalSize, (attr & PSP_TLS_ATTR_HIGHMEM) != 0, name);
userMemory.ListBlocks();
ERROR_LOG(HLE, "UNIMPL %08x=ThreadManForUser_8DAFF657(%s, %d, %08x, %d, %d, %08x)", blockPtr, name, partitionid, attr, size, count, optionsPtr);
return blockPtr;
if (blockPtr == (u32) -1)
{
ERROR_LOG(HLE, "%08x=sceKernelCreateTls(%s, %d, %08x, %d, %d, %08x): failed to allocate memory", SCE_KERNEL_ERROR_NO_MEMORY, name, partition, attr, blockSize, count, optionsPtr);
return SCE_KERNEL_ERROR_NO_MEMORY;
}
TLS *tls = new TLS();
SceUID id = kernelObjects.Create(tls);
tls->ntls.size = sizeof(tls->ntls);
strncpy(tls->ntls.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
tls->ntls.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
tls->ntls.attr = attr;
tls->ntls.index = index;
tlsUsedIndexes[index] = true;
tls->ntls.blockSize = blockSize;
tls->ntls.totalBlocks = count;
tls->ntls.freeBlocks = count;
tls->ntls.numWaitThreads = 0;
tls->address = blockPtr;
tls->usage.resize(count, 0);
WARN_LOG(HLE, "%08x=sceKernelCreateTls(%s, %d, %08x, %d, %d, %08x)", id, name, partition, attr, blockSize, count, optionsPtr);
// TODO: just alignment?
if (optionsPtr != 0)
WARN_LOG(HLE, "sceKernelCreateTls(%s) unsupported options parameter: %08x", name, optionsPtr);
if ((attr & PSP_TLS_ATTR_PRIORITY) != 0)
WARN_LOG(HLE, "sceKernelCreateTls(%s) unsupported attr parameter: %08x", name, attr);
return id;
}
int ThreadManForUser_32BF938E(SceUID uid)
// Parameters are an educated guess.
int sceKernelDeleteTls(SceUID uid)
{
ERROR_LOG(HLE, "UNIMPL ThreadManForUser_32BF938E(%08x)", uid);
userMemory.Free(uid);
return 0;
WARN_LOG(HLE, "sceKernelDeleteTls(%08x)", uid);
u32 error;
TLS *tls = kernelObjects.Get<TLS>(uid, error);
if (tls)
{
// TODO: Wake waiting threads, probably?
userMemory.Free(tls->address);
tlsUsedIndexes[tls->ntls.index] = false;
kernelObjects.Destroy<TLS>(uid);
}
return error;
}
int Kernel_Library_FA835CDE(SceUID uid)
int sceKernelAllocateTls(SceUID uid)
{
ERROR_LOG(HLE, "UNIMPL Kernel_Library_FA835CDE(%08x)", uid);
return uid;
// TODO: Allocate downward if PSP_TLS_ATTR_HIGHMEM?
WARN_LOG(HLE, "UNIMPL sceKernelAllocateTls(%08x)", uid);
u32 error;
TLS *tls = kernelObjects.Get<TLS>(uid, error);
if (tls)
{
SceUID threadID = __KernelGetCurThread();
int allocBlock = -1;
// If the thread already has one, return it.
for (size_t i = 0; i < tls->ntls.totalBlocks && allocBlock == -1; ++i)
{
if (tls->usage[i] == threadID)
allocBlock = i;
}
if (allocBlock == -1)
{
for (size_t i = 0; i < tls->ntls.totalBlocks && allocBlock == -1; ++i)
{
// The PSP doesn't give the same block out twice in a row, even if freed.
if (tls->usage[tls->next] == 0)
allocBlock = tls->next;
tls->next = (tls->next + 1) % tls->ntls.blockSize;
}
if (allocBlock != -1)
{
tls->usage[allocBlock] = threadID;
--tls->ntls.freeBlocks;
}
}
if (allocBlock == -1)
{
// TODO: Wait here, wake when one is free.
ERROR_LOG(HLE, "sceKernelAllocateTls: should wait");
return -1;
}
return tls->address + allocBlock * tls->ntls.blockSize;
}
else
return error;
}
// Parameters are an educated guess.
int sceKernelFreeTls(SceUID uid)
{
WARN_LOG(HLE, "UNIMPL sceKernelFreeTls(%08x)", uid);
u32 error;
TLS *tls = kernelObjects.Get<TLS>(uid, error);
if (tls)
{
SceUID threadID = __KernelGetCurThread();
// If the thread already has one, return it.
int freeBlock = -1;
for (size_t i = 0; i < tls->ntls.totalBlocks; ++i)
{
if (tls->usage[i] == threadID)
{
freeBlock = i;
break;
}
}
if (freeBlock != -1)
{
// TODO: Free anyone waiting for a free block.
tls->usage[freeBlock] = 0;
++tls->ntls.freeBlocks;
return 0;
}
// TODO: Correct error code.
else
return -1;
}
else
return error;
}
// Parameters are an educated guess.
int sceKernelReferTlsStatus(SceUID uid, u32 infoPtr)
{
DEBUG_LOG(HLE, "sceKernelReferTlsStatus(%08x, %08x)", uid, infoPtr);
u32 error;
TLS *tls = kernelObjects.Get<TLS>(uid, error);
if (tls)
{
// TODO: Check size.
Memory::WriteStruct(infoPtr, &tls->ntls);
return 0;
}
else
return error;
}
const HLEFunction SysMemUserForUser[] = {

View File

@ -35,6 +35,7 @@ void __KernelMemoryShutdown();
KernelObject *__KernelMemoryFPLObject();
KernelObject *__KernelMemoryVPLObject();
KernelObject *__KernelMemoryPMBObject();
KernelObject *__KernelTlsObject();
SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize, u32 optPtr);
int sceKernelDeleteVpl(SceUID uid);
@ -56,8 +57,10 @@ void sceKernelReferFplStatus();
int sceKernelGetCompiledSdkVersion();
SceUID ThreadManForUser_8DAFF657(const char *name, u32 partitionid, u32 attr, u32 size, u32 count, u32 optionsPtr);
int ThreadManForUser_32BF938E(SceUID uid);
int Kernel_Library_FA835CDE(SceUID uid);
SceUID sceKernelCreateTls(const char *name, u32 partitionid, u32 attr, u32 size, u32 count, u32 optionsPtr);
int sceKernelDeleteTls(SceUID uid);
int sceKernelAllocateTls(SceUID uid);
int sceKernelFreeTls(SceUID uid);
int sceKernelReferTlsStatus(SceUID uid, u32 infoPtr);
void Register_SysMemUserForUser();