From 79c5c93d351dd2eed359147f0e546e7ad0b1bb4d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 20 Sep 2022 19:25:32 -0700 Subject: [PATCH] Kernel: Match index lookup behavior for tls. It might be the uids it returns always follow this format. This makes the test almost pass, outside psplink using more memory (test should be adjusted to compensate.) --- Core/HLE/sceKernelMemory.cpp | 111 +++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 935cbc84826c..318cae7d0cfe 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -2174,68 +2174,89 @@ int sceKernelDeleteTlspl(SceUID uid) return error; } -int sceKernelGetTlsAddr(SceUID uid) -{ - // TODO: Allocate downward if PSP_TLSPL_ATTR_HIGHMEM? - DEBUG_LOG(SCEKERNEL, "sceKernelGetTlsAddr(%08x)", uid); +struct FindTLSByIndexArg { + int index; + TLSPL *result = nullptr; +}; +static bool FindTLSByIndex(TLSPL *possible, FindTLSByIndexArg *state) { + if (possible->ntls.index == state->index) { + state->result = possible; + return false; + } + return true; +} + +int sceKernelGetTlsAddr(SceUID uid) { if (!__KernelIsDispatchEnabled() || __IsInInterrupt()) - return 0; + return hleLogWarning(SCEKERNEL, 0, "dispatch disabled"); u32 error; TLSPL *tls = kernelObjects.Get(uid, error); - if (tls) + if (!tls) { + if (uid < 0) + return hleLogError(SCEKERNEL, 0, "tlspl not found"); + + // There's this weird behavior where it looks up by index. Maybe we shouldn't use uids... + if (!tlsplUsedIndexes[(uid >> 3) & 15]) + return hleLogError(SCEKERNEL, 0, "tlspl not found"); + + FindTLSByIndexArg state; + state.index = (uid >> 3) & 15; + kernelObjects.Iterate(&FindTLSByIndex, &state); + if (!state.result) + return hleLogError(SCEKERNEL, 0, "tlspl not found"); + + tls = state.result; + } + + SceUID threadID = __KernelGetCurThread(); + int allocBlock = -1; + bool needsClear = false; + + // If the thread already has one, return it. + for (size_t i = 0; i < tls->ntls.totalBlocks && allocBlock == -1; ++i) { - SceUID threadID = __KernelGetCurThread(); - int allocBlock = -1; - bool needsClear = false; + if (tls->usage[i] == threadID) + allocBlock = (int) i; + } - // If the thread already has one, return it. + if (allocBlock == -1) + { for (size_t i = 0; i < tls->ntls.totalBlocks && allocBlock == -1; ++i) { - if (tls->usage[i] == threadID) - allocBlock = (int) 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.totalBlocks; - } - - if (allocBlock != -1) - { - tls->usage[allocBlock] = threadID; - tlsplThreadEndChecks.insert(std::make_pair(threadID, uid)); - --tls->ntls.freeBlocks; - needsClear = true; - } + // 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.totalBlocks; } - if (allocBlock == -1) + if (allocBlock != -1) { - tls->waitingThreads.push_back(threadID); - __KernelWaitCurThread(WAITTYPE_TLSPL, uid, 1, 0, false, "allocate tls"); - return 0; + tls->usage[allocBlock] = threadID; + tlsplThreadEndChecks.insert(std::make_pair(threadID, uid)); + --tls->ntls.freeBlocks; + needsClear = true; } + } - u32 alignedSize = (tls->ntls.blockSize + tls->alignment - 1) & ~(tls->alignment - 1); - u32 allocAddress = tls->address + allocBlock * alignedSize; - NotifyMemInfo(MemBlockFlags::SUB_ALLOC, allocAddress, tls->ntls.blockSize, "TlsAddr"); + if (allocBlock == -1) + { + tls->waitingThreads.push_back(threadID); + __KernelWaitCurThread(WAITTYPE_TLSPL, uid, 1, 0, false, "allocate tls"); + return hleLogDebug(SCEKERNEL, 0, "waiting for tls alloc"); + } - // We clear the blocks upon first allocation (and also when they are freed, both are necessary.) - if (needsClear) { - Memory::Memset(allocAddress, 0, tls->ntls.blockSize, "TlsAddr"); - } + u32 alignedSize = (tls->ntls.blockSize + tls->alignment - 1) & ~(tls->alignment - 1); + u32 allocAddress = tls->address + allocBlock * alignedSize; + NotifyMemInfo(MemBlockFlags::SUB_ALLOC, allocAddress, tls->ntls.blockSize, "TlsAddr"); - return allocAddress; + // We clear the blocks upon first allocation (and also when they are freed, both are necessary.) + if (needsClear) { + Memory::Memset(allocAddress, 0, tls->ntls.blockSize, "TlsAddr"); } - else - return 0; + + return hleLogDebug(SCEKERNEL, allocAddress); } // Parameters are an educated guess.