/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.HLE.kernel.types; import static jpcsp.HLE.modules.SysMemUserForUser.PSP_SMEM_High; import static jpcsp.HLE.modules.SysMemUserForUser.PSP_SMEM_HighAligned; import static jpcsp.HLE.modules.SysMemUserForUser.PSP_SMEM_Low; import static jpcsp.HLE.modules.SysMemUserForUser.PSP_SMEM_LowAligned; import static jpcsp.HLE.modules.ThreadManForUser.PSP_ATTR_ADDR_HIGH; import static jpcsp.util.Utilities.alignUp; import jpcsp.Memory; import jpcsp.HLE.Modules; import jpcsp.HLE.kernel.managers.SceUidManager; import jpcsp.HLE.modules.SysMemUserForUser.SysMemInfo; /** * Thread-local storage introduced in PSP 6.20. * */ public class SceKernelTls { public String name; public int attr; public int blockSize; public int alignedBlockSize; public int numberBlocks; public int uid; private static final String uidPurpose = "SceKernelTls"; private SysMemInfo sysMemInfo; private int[] threadIds; public SceKernelTls(String name, int partitionId, int attr, int blockSize, int alignedBlockSize, int numberBlocks, int alignment) { blockSize = alignUp(blockSize, 3); this.name = name; this.attr = attr; this.blockSize = blockSize; this.alignedBlockSize = alignedBlockSize; this.numberBlocks = numberBlocks; int type = alignment == 0 ? PSP_SMEM_Low : PSP_SMEM_LowAligned; if ((attr & PSP_ATTR_ADDR_HIGH) != 0) { type = alignment == 0 ? PSP_SMEM_High : PSP_SMEM_HighAligned; } int size = alignedBlockSize * numberBlocks; sysMemInfo = Modules.SysMemUserForUserModule.malloc(partitionId, name, type, size, alignment); uid = SceUidManager.getNewUid(uidPurpose); threadIds = new int[numberBlocks]; } public void free() { Memory.getInstance().memset(sysMemInfo.addr, (byte) 0, sysMemInfo.allocatedSize); Modules.SysMemUserForUserModule.free(sysMemInfo); sysMemInfo = null; SceUidManager.releaseUid(uid, uidPurpose); uid = -1; } public int getBaseAddress() { if (sysMemInfo == null) { return 0; } return sysMemInfo.addr; } public void freeTlsAddress() { if (sysMemInfo == null) { return; } int currentThreadId = Modules.ThreadManForUserModule.getCurrentThreadID(); for (int i = 0; i < threadIds.length; i++) { if (threadIds[i] == currentThreadId) { threadIds[i] = 0; break; } } } public int getTlsAddress() { if (sysMemInfo == null) { return 0; } int currentThreadId = Modules.ThreadManForUserModule.getCurrentThreadID(); int block = -1; // If a block has already been allocated for this thread, use it for (int i = 0; i < threadIds.length; i++) { if (threadIds[i] == currentThreadId) { block = i; break; } } boolean needsClear = false; if (block < 0) { // Return the first free block for (int i = 0; i < threadIds.length; i++) { if (threadIds[i] == 0) { block = i; threadIds[block] = currentThreadId; needsClear = true; break; } } if (block < 0) { return 0; } } int address = sysMemInfo.addr + block * alignedBlockSize; if (needsClear) { Memory.getInstance().memset(address, (byte) 0, blockSize); } return address; } }