/* 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.modules; import static jpcsp.Allegrex.Common._a1; import static jpcsp.Allegrex.Common._t3; import jpcsp.HLE.BufferInfo; import jpcsp.HLE.BufferInfo.Usage; import jpcsp.HLE.CanBeNull; import jpcsp.HLE.HLEFunction; import jpcsp.HLE.HLEModule; import jpcsp.HLE.HLEUnimplemented; import jpcsp.HLE.PspString; import jpcsp.HLE.StringInfo; import jpcsp.HLE.TPointer; import jpcsp.HLE.TPointer32; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import jpcsp.Emulator; import jpcsp.Memory; import jpcsp.MemoryMap; import jpcsp.Allegrex.CpuState; import jpcsp.Debugger.DumpDebugState; import jpcsp.HLE.Modules; import jpcsp.HLE.kernel.managers.SceUidManager; import jpcsp.HLE.kernel.types.MemoryChunk; import jpcsp.HLE.kernel.types.MemoryChunkList; import jpcsp.HLE.kernel.types.SceKernelErrors; import jpcsp.memory.IMemoryReader; import jpcsp.memory.IMemoryWriter; import jpcsp.memory.MemoryReader; import jpcsp.memory.MemoryWriter; import jpcsp.util.Utilities; import org.apache.log4j.Logger; /* * TODO list: * 1. Use the partitionid in functions that use it as a parameter. * -> Info: * 1 = kernel, 2 = user, 3 = me, 4 = kernel mirror (from potemkin/dash) * http://forums.ps2dev.org/viewtopic.php?p=75341#75341 * 8 = slim, topaddr = 0x8A000000, size = 0x1C00000 (28 MB), attr = 0x0C * 8 = slim, topaddr = 0x8BC00000, size = 0x400000 (4 MB), attr = 0x0C * * 2. Implement format string parsing and reading variable number of parameters * in sceKernelPrintf. */ public class SysMemUserForUser extends HLEModule { public static Logger log = Modules.getLogger("SysMemUserForUser"); protected static Logger stdout = Logger.getLogger("stdout"); protected static HashMap<Integer, SysMemInfo> blockList; protected static MemoryChunkList[] freeMemoryChunks; protected int firmwareVersion = 150; public static final int defaultSizeAlignment = 256; // PspSysMemBlockTypes public static final int PSP_SMEM_Low = 0; public static final int PSP_SMEM_High = 1; public static final int PSP_SMEM_Addr = 2; public static final int PSP_SMEM_LowAligned = 3; public static final int PSP_SMEM_HighAligned = 4; public static final int KERNEL_PARTITION_ID = 1; public static final int USER_PARTITION_ID = 2; public static final int VSHELL_PARTITION_ID = 5; protected boolean started = false; private int compiledSdkVersion; private int compilerVersion; @Override public void load() { reset(); super.load(); } @Override public void start() { if (!started) { reset(); started = true; } compiledSdkVersion = 0; compilerVersion = 0; super.start(); } @Override public void stop() { started = false; super.stop(); } private MemoryChunkList createMemoryChunkList(int startAddr, int endAddr) { startAddr &= Memory.addressMask; endAddr &= Memory.addressMask; MemoryChunk initialMemory = new MemoryChunk(startAddr, endAddr - startAddr + 1); return new MemoryChunkList(initialMemory); } public void reset() { reset(false); } public void reset(boolean preserveKernelMemory) { if (blockList == null || freeMemoryChunks == null) { preserveKernelMemory = false; } if (preserveKernelMemory) { List<SysMemInfo> toBeFreed = new LinkedList<SysMemInfo>(); for (SysMemInfo sysMemInfo: blockList.values()) { if (sysMemInfo.partitionid == USER_PARTITION_ID) { toBeFreed.add(sysMemInfo); } } for (SysMemInfo sysMemInfo : toBeFreed) { sysMemInfo.free(); } } else { blockList = new HashMap<Integer, SysMemInfo>(); } if (!preserveKernelMemory) { int vshellSize = 0x400000; // free memory chunks for each partition freeMemoryChunks = new MemoryChunkList[6]; freeMemoryChunks[KERNEL_PARTITION_ID] = createMemoryChunkList(MemoryMap.START_KERNEL, MemoryMap.END_KERNEL - vshellSize); freeMemoryChunks[VSHELL_PARTITION_ID] = createMemoryChunkList(MemoryMap.END_KERNEL + 1 - vshellSize, MemoryMap.END_KERNEL); } freeMemoryChunks[USER_PARTITION_ID] = createMemoryChunkList(MemoryMap.START_USERSPACE, MemoryMap.END_USERSPACE); } public void setMemory64MB(boolean isMemory64MB) { if (isMemory64MB) { setMemorySize(MemoryMap.END_RAM_64MB - MemoryMap.START_RAM + 1); // 60 MB } else { setMemorySize(MemoryMap.END_RAM_32MB - MemoryMap.START_RAM + 1); // 32 MB } } public void setMemorySize(int memorySize) { if (MemoryMap.SIZE_RAM != memorySize) { int previousMemorySize = MemoryMap.SIZE_RAM; MemoryMap.END_RAM = MemoryMap.START_RAM + memorySize - 1; MemoryMap.END_USERSPACE = MemoryMap.END_RAM; MemoryMap.SIZE_RAM = MemoryMap.END_RAM - MemoryMap.START_RAM + 1; int kernelSize32 = (MemoryMap.END_KERNEL - MemoryMap.START_KERNEL + 1) >> 2; int[] savedKernelMemory = new int[kernelSize32]; IMemoryReader memoryReader = MemoryReader.getMemoryReader(MemoryMap.START_KERNEL, 4); for (int i = 0; i < kernelSize32; i++) { savedKernelMemory[i] = memoryReader.readNext(); } if (!Memory.getInstance().allocate()) { log.error(String.format("Failed to resize the PSP memory from 0x%X to 0x%X", previousMemorySize, memorySize)); Emulator.PauseEmuWithStatus(Emulator.EMU_STATUS_MEM_ANY); } IMemoryWriter memoryWriter = MemoryWriter.getMemoryWriter(MemoryMap.START_KERNEL, 4); for (int i = 0; i < kernelSize32; i++) { memoryWriter.writeNext(savedKernelMemory[i]); } reset(true); } } public static class SysMemInfo implements Comparable<SysMemInfo> { public final int uid; public final int partitionid; public final String name; public final int type; public int size; public int allocatedSize; public final int addr; public SysMemInfo(int partitionid, String name, int type, int size, int allocatedSize, int addr) { this.partitionid = partitionid; this.name = name; this.type = type; this.size = size; this.allocatedSize = allocatedSize; this.addr = addr; uid = SceUidManager.getNewUid("SysMem"); blockList.put(uid, this); } @Override public String toString() { return String.format("SysMemInfo[addr=0x%08X-0x%08X, uid=0x%X, partition=%d, name='%s', type=%s, size=0x%X (allocated=0x%X)]", addr, addr + allocatedSize, uid, partitionid, name, getTypeName(type), size, allocatedSize); } public void free() { blockList.remove(uid); } @Override public int compareTo(SysMemInfo o) { if (addr == o.addr) { log.warn("Set invariant broken for SysMemInfo " + this); return 0; } return addr < o.addr ? -1 : 1; } } static protected String getTypeName(int type) { String typeName; switch (type) { case PSP_SMEM_Low: typeName = "PSP_SMEM_Low"; break; case PSP_SMEM_High: typeName = "PSP_SMEM_High"; break; case PSP_SMEM_Addr: typeName = "PSP_SMEM_Addr"; break; case PSP_SMEM_LowAligned: typeName = "PSP_SMEM_LowAligned"; break; case PSP_SMEM_HighAligned: typeName = "PSP_SMEM_HighAligned"; break; default: typeName = "UNHANDLED " + type; break; } return typeName; } private boolean isValidPartitionId(int partitionid) { return partitionid >= 0 && partitionid < freeMemoryChunks.length && freeMemoryChunks[partitionid] != null; } // Allocates to 256-byte alignment public SysMemInfo malloc(int partitionid, String name, int type, int size, int addr) { if (freeMemoryChunks == null) { return null; } int allocatedAddress = 0; int allocatedSize = 0; if (isValidPartitionId(partitionid)) { MemoryChunkList freeMemoryChunk = freeMemoryChunks[partitionid]; int alignment = defaultSizeAlignment - 1; // The allocated size has not to be aligned to the requested alignment // (for PSP_SMEM_LowAligned or PSP_SMEM_HighAligned), // it is only aligned to the default size alignment. allocatedSize = Utilities.alignUp(size, alignment); if (type == PSP_SMEM_LowAligned || type == PSP_SMEM_HighAligned) { // Use the alignment provided in the addr parameter alignment = addr - 1; } switch (type) { case PSP_SMEM_Low: case PSP_SMEM_LowAligned: allocatedAddress = freeMemoryChunk.allocLow(allocatedSize, alignment); break; case PSP_SMEM_High: case PSP_SMEM_HighAligned: allocatedAddress = freeMemoryChunk.allocHigh(allocatedSize, alignment); break; case PSP_SMEM_Addr: allocatedAddress = freeMemoryChunk.alloc(addr, allocatedSize); break; default: log.warn(String.format("malloc: unknown type %s", getTypeName(type))); } } SysMemInfo sysMemInfo; if (allocatedAddress == 0) { log.warn(String.format("malloc cannot allocate partition=%d, name='%s', type=%s, size=0x%X, addr=0x%08X, maxFreeMem=0x%X, totalFreeMem=0x%X", partitionid, name, getTypeName(type), size, addr, maxFreeMemSize(partitionid), totalFreeMemSize(partitionid))); if (log.isTraceEnabled()) { log.trace("Free list: " + getDebugFreeMem()); log.trace("Allocated blocks:\n" + getDebugAllocatedMem() + "\n"); } sysMemInfo = null; } else { sysMemInfo = new SysMemInfo(partitionid, name, type, size, allocatedSize, allocatedAddress); if (log.isDebugEnabled()) { log.debug(String.format("malloc partition=%d, name='%s', type=%s, size=0x%X, addr=0x%08X: returns 0x%08X", partitionid, name, getTypeName(type), size, addr, allocatedAddress)); if (log.isTraceEnabled()) { log.trace("Free list after malloc: " + getDebugFreeMem()); log.trace("Allocated blocks after malloc:\n" + getDebugAllocatedMem() + "\n"); } } } return sysMemInfo; } public String getDebugFreeMem() { return freeMemoryChunks[USER_PARTITION_ID].toString(); } public String getDebugAllocatedMem() { StringBuilder result = new StringBuilder(); // Sort allocated blocks by address List<SysMemInfo> sortedBlockList = Collections.list(Collections.enumeration(blockList.values())); Collections.sort(sortedBlockList); for (SysMemInfo sysMemInfo : sortedBlockList) { if (result.length() > 0) { result.append("\n"); } result.append(sysMemInfo.toString()); } return result.toString(); } public void free(SysMemInfo info) { if (info != null) { info.free(); MemoryChunk memoryChunk = new MemoryChunk(info.addr, info.allocatedSize); freeMemoryChunks[info.partitionid].add(memoryChunk); if (log.isDebugEnabled()) { log.debug(String.format("free %s", info.toString())); if (log.isTraceEnabled()) { log.trace("Free list after free: " + getDebugFreeMem()); log.trace("Allocated blocks after free:\n" + getDebugAllocatedMem() + "\n"); } } } } public int maxFreeMemSize(int partitionid) { int maxFreeMemSize = 0; if (isValidPartitionId(partitionid)) { for (MemoryChunk memoryChunk = freeMemoryChunks[partitionid].getLowMemoryChunk(); memoryChunk != null; memoryChunk = memoryChunk.next) { if (memoryChunk.size > maxFreeMemSize) { maxFreeMemSize = memoryChunk.size; } } } return maxFreeMemSize; } public int totalFreeMemSize(int partitionid) { int totalFreeMemSize = 0; if (isValidPartitionId(partitionid)) { for (MemoryChunk memoryChunk = freeMemoryChunks[partitionid].getLowMemoryChunk(); memoryChunk != null; memoryChunk = memoryChunk.next) { totalFreeMemSize += memoryChunk.size; } } return totalFreeMemSize; } public SysMemInfo getSysMemInfo(int uid) { return blockList.get(uid); } public SysMemInfo separateMemoryBlock(SysMemInfo info, int size) { int newAddr = info.addr + size; int newSize = info.size - size; int newAllocatedSize = info.allocatedSize - size; // Create a new memory block SysMemInfo newSysMemInfo = new SysMemInfo(info.partitionid, info.name, info.type, newSize, newAllocatedSize, newAddr); // Resize the previous memory block info.size -= newSize; info.allocatedSize -= newAllocatedSize; return newSysMemInfo; } /** @param firmwareVersion : in this format: ABB, where A = major and B = minor, for example 271 */ public void setFirmwareVersion(int firmwareVersion) { this.firmwareVersion = firmwareVersion; } public int getFirmwareVersion() { return firmwareVersion; } // note: we're only looking at user memory, so 0x08800000 - 0x0A000000 // this is mainly to make it fit on one console line public void dumpSysMemInfo() { final int MEMORY_SIZE = 0x1800000; final int SLOT_COUNT = 64; // 0x60000 final int SLOT_SIZE = MEMORY_SIZE / SLOT_COUNT; // 0x60000 boolean[] allocated = new boolean[SLOT_COUNT]; boolean[] fragmented = new boolean[SLOT_COUNT]; int allocatedSize = 0; int fragmentedSize = 0; for (Iterator<SysMemInfo> it = blockList.values().iterator(); it.hasNext();) { SysMemInfo info = it.next(); for (int i = info.addr; i < info.addr + info.size; i += SLOT_SIZE) { if (i >= 0x08800000 && i < 0x0A000000) { allocated[(i - 0x08800000) / SLOT_SIZE] = true; } } allocatedSize += info.size; } for (MemoryChunk memoryChunk = freeMemoryChunks[USER_PARTITION_ID].getLowMemoryChunk(); memoryChunk != null; memoryChunk = memoryChunk.next) { for (int i = memoryChunk.addr; i < memoryChunk.addr + memoryChunk.size; i += SLOT_SIZE) { if (i >= 0x08800000 && i < 0x0A000000) { fragmented[(i - 0x08800000) / SLOT_SIZE] = true; } } fragmentedSize += memoryChunk.size; } StringBuilder allocatedDiagram = new StringBuilder(); allocatedDiagram.append("["); for (int i = 0; i < SLOT_COUNT; i++) { allocatedDiagram.append(allocated[i] ? "X" : " "); } allocatedDiagram.append("]"); StringBuilder fragmentedDiagram = new StringBuilder(); fragmentedDiagram.append("["); for (int i = 0; i < SLOT_COUNT; i++) { fragmentedDiagram.append(fragmented[i] ? "X" : " "); } fragmentedDiagram.append("]"); DumpDebugState.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); DumpDebugState.log(String.format("Allocated memory: %08X %d bytes", allocatedSize, allocatedSize)); DumpDebugState.log(allocatedDiagram.toString()); DumpDebugState.log(String.format("Fragmented memory: %08X %d bytes", fragmentedSize, fragmentedSize)); DumpDebugState.log(fragmentedDiagram.toString()); DumpDebugState.log("Free list: " + getDebugFreeMem()); DumpDebugState.log("Allocated blocks:\n" + getDebugAllocatedMem() + "\n"); } public String hleKernelSprintf(CpuState cpu, String format, Object[] formatParameters) { String formattedMsg = format; try { // Translate the C-like format string to a Java format string: // - %u or %i -> %d // - %4u -> %4d // - %lld or %ld -> %d // - %llx or %lx -> %x // - %p -> %08X String javaMsg = format; javaMsg = javaMsg.replaceAll("\\%(\\d*)l?l?[uid]", "%$1d"); javaMsg = javaMsg.replaceAll("\\%(\\d*)l?l?([xX])", "%$1$2"); javaMsg = javaMsg.replaceAll("\\%p", "%08X"); // Support for "%s" (at any place and can occur multiple times) int index = -1; for (int parameterIndex = 0; parameterIndex < formatParameters.length; parameterIndex++) { index = javaMsg.indexOf('%', index + 1); if (index < 0) { break; } String parameterFormat = javaMsg.substring(index); if (parameterFormat.startsWith("%s")) { // Convert an integer address to a String by reading // the String at the given address formatParameters[parameterIndex] = Utilities.readStringZ(((Integer) formatParameters[parameterIndex]).intValue()); } } // String.format: If there are more arguments than format specifiers, the extra arguments are ignored. formattedMsg = String.format(javaMsg, formatParameters); } catch (Exception e) { // Ignore formatting exception } return formattedMsg; } public String hleKernelSprintf(CpuState cpu, String format, int firstRegister) { // For now, use only the 7 register parameters: $a1-$a3, $t0-$t3 // Further parameters are retrieved from the stack (assume max. 10 stack parameters). int registerParameters = _t3 - firstRegister + 1; Object[] formatParameters = new Object[registerParameters + 10]; for (int i = 0; i < registerParameters; i++) { formatParameters[i] = cpu.getRegister(firstRegister + i); } Memory mem = Memory.getInstance(); for (int i = registerParameters; i < formatParameters.length; i++) { formatParameters[i] = mem.read32(cpu._sp + ((i - registerParameters) << 2)); } return hleKernelSprintf(cpu, format, formatParameters); } public int hleKernelPrintf(CpuState cpu, PspString formatString, Logger logger) { // Format and print the message to the logger if (logger.isInfoEnabled()) { String formattedMsg = hleKernelSprintf(cpu, formatString.getString(), _a1); logger.info(formattedMsg); } return 0; } public int hleKernelGetCompiledSdkVersion() { return compiledSdkVersion; } protected void hleSetCompiledSdkVersion(int sdkVersion) { compiledSdkVersion = sdkVersion; } public int hleKernelGetCompilerVersion() { return compilerVersion; } @HLEFunction(nid = 0xA291F107, version = 150) public int sceKernelMaxFreeMemSize() { int maxFreeMemSize = maxFreeMemSize(USER_PARTITION_ID); // Some games expect size to be rounded down in 16 bytes block maxFreeMemSize &= ~15; if (log.isDebugEnabled()) { log.debug(String.format("sceKernelMaxFreeMemSize returning %d(hex=0x%1$X)", maxFreeMemSize)); } return maxFreeMemSize; } @HLEFunction(nid = 0xF919F628, version = 150) public int sceKernelTotalFreeMemSize() { int totalFreeMemSize = totalFreeMemSize(USER_PARTITION_ID); if (log.isDebugEnabled()) { log.debug(String.format("sceKernelTotalFreeMemSize returning %d(hex=0x%1$X)", totalFreeMemSize)); } return totalFreeMemSize; } @HLEFunction(nid = 0x237DBD4F, version = 150) public int sceKernelAllocPartitionMemory(int partitionid, String name, int type, int size, int addr) { addr &= Memory.addressMask; if (type < PSP_SMEM_Low || type > PSP_SMEM_HighAligned) { return SceKernelErrors.ERROR_KERNEL_ILLEGAL_MEMBLOCK_ALLOC_TYPE; } SysMemInfo info = malloc(partitionid, name, type, size, addr); if (info == null) { return SceKernelErrors.ERROR_KERNEL_FAILED_ALLOC_MEMBLOCK; } return info.uid; } @HLEFunction(nid = 0xB6D61D02, version = 150) public int sceKernelFreePartitionMemory(int uid) { SceUidManager.checkUidPurpose(uid, "SysMem", true); SysMemInfo info = blockList.remove(uid); if (info == null) { log.warn(String.format("sceKernelFreePartitionMemory unknown uid=0x%X", uid)); return SceKernelErrors.ERROR_KERNEL_ILLEGAL_CHUNK_ID; } free(info); return 0; } @HLEFunction(nid = 0x9D9A5BA1, version = 150) public int sceKernelGetBlockHeadAddr(int uid) { SceUidManager.checkUidPurpose(uid, "SysMem", true); SysMemInfo info = blockList.get(uid); if (info == null) { log.warn(String.format("sceKernelGetBlockHeadAddr unknown uid=0x%X", uid)); return SceKernelErrors.ERROR_KERNEL_ILLEGAL_CHUNK_ID; } return info.addr; } @HLEFunction(nid = 0x13A5ABEF, version = 150) public int sceKernelPrintf(CpuState cpu, PspString formatString) { return hleKernelPrintf(cpu, formatString, stdout); } @HLEFunction(nid = 0x3FC9AE6A, version = 150) public int sceKernelDevkitVersion() { int major = firmwareVersion / 100; int minor = (firmwareVersion / 10) % 10; int revision = firmwareVersion % 10; int devkitVersion = (major << 24) | (minor << 16) | (revision << 8) | 0x10; if (log.isDebugEnabled()) { log.debug(String.format("sceKernelDevkitVersion returning 0x%08X", devkitVersion)); } return devkitVersion; } @HLEFunction(nid = 0xD8DE5C1E, version = 150) public int SysMemUserForUser_D8DE5C1E() { // Seems to always return 0... return 0; } @HLEFunction(nid = 0xFC114573, version = 200) public int sceKernelGetCompiledSdkVersion() { if (log.isDebugEnabled()) { log.debug(String.format("sceKernelGetCompiledSdkVersion returning 0x%08X", compiledSdkVersion)); } return compiledSdkVersion; } @HLEFunction(nid = 0x7591C7DB, version = 200) public int sceKernelSetCompiledSdkVersion(int sdkVersion) { hleSetCompiledSdkVersion(sdkVersion); return 0; } @HLEFunction(nid = 0xF77D77CB, version = 200) public int sceKernelSetCompilerVersion(int compilerVersion) { this.compilerVersion = compilerVersion; return 0; } @HLEUnimplemented @HLEFunction(nid = 0xA6848DF8, version = 200) public int SysMemUserForUser_A6848DF8() { return 0; } @HLEFunction(nid = 0x2A3E5280, version = 280) public int sceKernelQueryMemoryInfo(int address, @CanBeNull @BufferInfo(usage=Usage.out) TPointer32 partitionId, @CanBeNull @BufferInfo(usage=Usage.out) TPointer32 memoryBlockId) { int result = SceKernelErrors.ERROR_KERNEL_ILLEGAL_ADDR; for (Integer key : blockList.keySet()) { SysMemInfo info = blockList.get(key); if (info != null && info.addr <= address && address < info.addr + info.size) { partitionId.setValue(info.partitionid); memoryBlockId.setValue(info.uid); result = 0; break; } } return result; } @HLEUnimplemented @HLEFunction(nid = 0x39F49610, version = 280) public int sceKernelGetPTRIG() { return 0; } @HLEUnimplemented @HLEFunction(nid = 0x6231A71D, version = 280) public int sceKernelSetPTRIG() { return 0; } // sceKernelFreeMemoryBlock (internal name) @HLEFunction(nid = 0x50F61D8A, version = 352) public int SysMemUserForUser_50F61D8A(int uid) { SysMemInfo info = blockList.remove(uid); if (info == null) { log.warn("SysMemUserForUser_50F61D8A(uid=0x" + Integer.toHexString(uid) + ") unknown uid"); return SceKernelErrors.ERROR_KERNEL_UNKNOWN_UID; } free(info); return 0; } @HLEFunction(nid = 0xACBD88CA, version = 352) public int sceKernelTotalMemSize() { return MemoryMap.SIZE_RAM; } // sceKernelGetMemoryBlockAddr (internal name) @HLEFunction(nid = 0xDB83A952, version = 352) public int SysMemUserForUser_DB83A952(int uid, TPointer32 addr) { SysMemInfo info = blockList.get(uid); if (info == null) { log.warn(String.format("SysMemUserForUser_DB83A952 uid=0x%X, addr=%s: unknown uid", uid, addr)); return SceKernelErrors.ERROR_KERNEL_UNKNOWN_UID; } addr.setValue(info.addr); return 0; } // sceKernelAllocMemoryBlock (internal name) @HLEFunction(nid = 0xFE707FDF, version = 352) public int SysMemUserForUser_FE707FDF(@StringInfo(maxLength=32) PspString name, int type, int size, @CanBeNull TPointer paramsAddr) { if (paramsAddr.isNotNull()) { int length = paramsAddr.getValue32(); if (length != 4) { log.warn(String.format("SysMemUserForUser_FE707FDF: unknown parameters with length=%d", length)); } } if (type < PSP_SMEM_Low || type > PSP_SMEM_High) { return SceKernelErrors.ERROR_KERNEL_ILLEGAL_MEMBLOCK_ALLOC_TYPE; } // Always allocate memory in user area (partitionid == 2). SysMemInfo info = malloc(SysMemUserForUser.USER_PARTITION_ID, name.getString(), type, size, 0); if (info == null) { return SceKernelErrors.ERROR_KERNEL_FAILED_ALLOC_MEMBLOCK; } return info.uid; } @HLEFunction(nid = 0x342061E5, version = 370) public int sceKernelSetCompiledSdkVersion370(int sdkVersion) { hleSetCompiledSdkVersion(sdkVersion); return 0; } @HLEFunction(nid = 0x315AD3A0, version = 380) public int sceKernelSetCompiledSdkVersion380_390(int sdkVersion) { hleSetCompiledSdkVersion(sdkVersion); return 0; } @HLEFunction(nid = 0xEBD5C3E6, version = 395) public int sceKernelSetCompiledSdkVersion395(int sdkVersion) { hleSetCompiledSdkVersion(sdkVersion); return 0; } @HLEFunction(nid = 0x91DE343C, version = 500) public int sceKernelSetCompiledSdkVersion500_505(int sdkVersion) { hleSetCompiledSdkVersion(sdkVersion); return 0; } @HLEFunction(nid = 0x7893F79A, version = 507) public int sceKernelSetCompiledSdkVersion507(int sdkVersion) { hleSetCompiledSdkVersion(sdkVersion); return 0; } @HLEFunction(nid = 0x35669D4C, version = 600) public int sceKernelSetCompiledSdkVersion600_602(int sdkVersion) { hleSetCompiledSdkVersion(sdkVersion); return 0; } @HLEFunction(nid = 0x1B4217BC, version = 603) public int sceKernelSetCompiledSdkVersion603_605(int sdkVersion) { hleSetCompiledSdkVersion(sdkVersion); return 0; } @HLEFunction(nid = 0x358CA1BB, version = 606) public int sceKernelSetCompiledSdkVersion606(int sdkVersion) { hleSetCompiledSdkVersion(sdkVersion); return 0; } @HLEFunction(nid = 0xC886B169, version = 150) public int sceKernelDevkitVersion_660() { return sceKernelDevkitVersion(); } }