/*
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 java.util.HashMap;
import jpcsp.Memory;
import jpcsp.State;
import jpcsp.HLE.BufferInfo;
import jpcsp.HLE.BufferInfo.LengthInfo;
import jpcsp.HLE.BufferInfo.Usage;
import jpcsp.HLE.HLEFunction;
import jpcsp.HLE.HLELogging;
import jpcsp.HLE.HLEModule;
import jpcsp.HLE.HLEUnimplemented;
import jpcsp.HLE.PspString;
import jpcsp.HLE.TPointer;
import jpcsp.HLE.Modules;
import jpcsp.HLE.TPointer32;
import jpcsp.HLE.kernel.managers.SceUidManager;
import jpcsp.HLE.kernel.types.MemoryChunk;
import jpcsp.HLE.kernel.types.MemoryChunkList;
import jpcsp.HLE.kernel.types.SceKernelGameInfo;
import jpcsp.HLE.modules.SysMemUserForUser.SysMemInfo;
import jpcsp.hardware.Model;
import jpcsp.memory.IMemoryWriter;
import jpcsp.memory.MemoryWriter;
import org.apache.log4j.Logger;
public class SysMemForKernel extends HLEModule {
public static Logger log = Modules.getLogger("SysMemForKernel");
protected HashMap<Integer, HeapInformation> heaps;
private String npEnv;
private int dnas;
private SysMemInfo gameInfoMem;
private SceKernelGameInfo gameInfo;
private SysMemInfo dummyControlBlock;
protected static class HeapInformation {
private static final String uidPurpose = "SysMemForKernel-Heap";
private static final int HEAP_BLOCK_HEADER_SIZE = 8;
protected final int uid;
protected final int partitionId;
protected final int size;
protected final int flags;
protected final String name;
protected SysMemInfo sysMemInfo;
protected int allocatedSize;
protected MemoryChunkList freeMemoryChunks;
public HeapInformation(int partitionId, int size, int flags, String name) {
this.partitionId = partitionId;
this.size = size;
this.flags = flags;
this.name = name;
allocatedSize = 0;
int type = SysMemUserForUser.PSP_SMEM_Low; // Which memory type to use?
sysMemInfo = Modules.SysMemUserForUserModule.malloc(partitionId, name, type, size, 0);
if (sysMemInfo == null) {
uid = -1;
} else {
MemoryChunk memoryChunk = new MemoryChunk(sysMemInfo.addr, size);
freeMemoryChunks = new MemoryChunkList(memoryChunk);
uid = SceUidManager.getNewUid(uidPurpose);
}
}
public void free() {
if (sysMemInfo != null) {
Modules.SysMemUserForUserModule.free(sysMemInfo);
sysMemInfo = null;
freeMemoryChunks = null;
SceUidManager.releaseUid(uid, uidPurpose);
}
}
public int allocBlock(int blockSize) {
if (freeMemoryChunks == null) {
return 0;
}
int addr = freeMemoryChunks.allocLow(blockSize + HEAP_BLOCK_HEADER_SIZE, 0);
if (addr == 0) {
return 0;
}
Memory.getInstance().write32(addr, blockSize);
return addr + HEAP_BLOCK_HEADER_SIZE;
}
public void freeBlock(int addr) {
addr -= HEAP_BLOCK_HEADER_SIZE;
int blockSize = Memory.getInstance().read32(addr);
MemoryChunk memoryChunk = new MemoryChunk(addr, blockSize);
freeMemoryChunks.add(memoryChunk);
}
}
@Override
public void start() {
heaps = new HashMap<Integer, SysMemForKernel.HeapInformation>();
npEnv = "np"; // Used in URLs to connect to the playstation sites
dnas = 0;
gameInfoMem = null;
gameInfo = new SceKernelGameInfo();
super.start();
}
@HLEFunction(nid = 0xA089ECA4, version = 150)
public int sceKernelMemset(TPointer destAddr, int data, int size) {
destAddr.memset((byte) data, size);
return 0;
}
@HLEFunction(nid = 0x8AE776AF, version = 660)
public int sceKernelMemset_660(TPointer destAddr, int data, int size) {
return sceKernelMemset(destAddr, data, size);
}
/**
* Create a heap.
*
* @param partitionId The UID of the partition where allocate the heap.
* @param size The size in bytes of the heap.
* @param flags Unknown, probably some flag or type, pass 1.
* @param name Name assigned to the new heap.
* @return The UID of the new heap, or if less than 0 an error.
*/
@HLELogging(level = "info")
@HLEFunction(nid = 0x1C1FBFE7, version = 150)
public int sceKernelCreateHeap(int partitionId, int size, int flags, String name) {
HeapInformation info = new HeapInformation(partitionId, size, flags, name);
if (info.uid >= 0) {
heaps.put(info.uid, info);
}
return info.uid;
}
/**
* Allocate a memory block from a heap.
*
* @param heapId The UID of the heap to allocate from.
* @param size The number of bytes to allocate.
* @return The address of the allocated memory block, or NULL on error.
*/
@HLEFunction(nid = 0x636C953B, version = 150)
public int sceKernelAllocHeapMemory(int heapId, int size) {
HeapInformation info = heaps.get(heapId);
if (info == null) {
return 0;
}
int addr = info.allocBlock(size);
if (log.isDebugEnabled()) {
log.debug(String.format("sceKernelAllocHeapMemory returning 0x%08X", addr));
}
return addr;
}
/**
* Free a memory block allocated from a heap.
*
* @param heapId The UID of the heap where block belongs.
* @param block The block of memory to free from the heap.
* @return 0 on success, < 0 on error.
*/
@HLEFunction(nid = 0x7B749390, version = 150)
public int sceKernelFreeHeapMemory(int heapId, TPointer block) {
HeapInformation info = heaps.get(heapId);
if (info == null) {
return -1;
}
info.freeBlock(block.getAddress());
return 0;
}
/**
* Delete a heap.
*
* @param heapId The UID of the heap to delete.
* @return 0 on success, < 0 on error.
*/
@HLEFunction(nid = 0xC9805775, version = 150)
public int sceKernelDeleteHeap(int heapId) {
HeapInformation info = heaps.remove(heapId);
if (info == null) {
return -1;
}
info.free();
return 0;
}
@HLEFunction(nid = 0x6373995D, version = 280)
public int sceKernelGetModel() {
int result = Model.getModel(); // <= 0 original, 1 slim
if (log.isDebugEnabled()) {
log.debug(String.format("sceKernelGetModel returning %d(%s)", result, Model.getModelName(result)));
}
return result;
}
@HLEFunction(nid = 0x07C586A1, version = 150)
public int sceKernelGetModel_660() {
int result = Model.getModel(); // <= 0 original, 1 slim
if (log.isDebugEnabled()) {
log.debug(String.format("sceKernelGetModel_660 returning %d(%s)", result, Model.getModelName(result)));
}
return result;
}
@HLEUnimplemented
@HLEFunction(nid = 0x945E45DA, version = 150)
public int SysMemUserForUser_945E45DA(TPointer unknown) {
unknown.setStringNZ(9, npEnv);
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x7FF2F35A, version = 150)
public int SysMemForKernel_7FF2F35A(TPointer unknown) {
return SysMemUserForUser_945E45DA(unknown);
}
@HLEUnimplemented
@HLEFunction(nid = 0xA03CB480, version = 660)
public int SysMemForKernel_A03CB480(TPointer unknown) {
npEnv = unknown.getStringNZ(8);
if (log.isDebugEnabled()) {
log.debug(String.format("SysMemForKernel_A03CB480 setting unknownString='%s'", npEnv));
}
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x807179E7, version = 150)
public int sceKernelSetParamSfo(PspString discId, int unknown1, int unknown2, PspString unknown3, int unknown4, int unknown5, PspString pspVersion) {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xBFD53FB7, version = 150)
public int sceKernelGetDNAS() {
return dnas;
}
@HLEUnimplemented
@HLEFunction(nid = 0x982A4779, version = 150)
public int sceKernelSetDNAS(int dnas) {
this.dnas = dnas;
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xEF29061C, version = 150)
public int sceKernelGetGameInfo() {
// Has no parameters
if (gameInfoMem == null) {
gameInfoMem = Modules.SysMemUserForUserModule.malloc(SysMemUserForUser.KERNEL_PARTITION_ID, "SceKernelGameInfo", SysMemUserForUser.PSP_SMEM_Low, SceKernelGameInfo.SIZEOF, 0);
}
gameInfo.gameId = State.discId;
gameInfo.sdkVersion = Modules.SysMemUserForUserModule.hleKernelGetCompiledSdkVersion();
gameInfo.compilerVersion = Modules.SysMemUserForUserModule.hleKernelGetCompilerVersion();
gameInfo.write(Memory.getInstance(), gameInfoMem.addr);
return gameInfoMem.addr;
}
@HLEFunction(nid = 0xB4F00CB5, version = 150)
public int sceKernelGetCompiledSdkVersion_660() {
return Modules.SysMemUserForUserModule.sceKernelGetCompiledSdkVersion();
}
@HLEFunction(nid = 0x7158CE7E, version = 150)
public int sceKernelAllocPartitionMemory_660(int partitionid, String name, int type, int size, int addr) {
return Modules.SysMemUserForUserModule.sceKernelAllocPartitionMemory(partitionid, name, type, size, addr);
}
@HLEFunction(nid = 0xC1A26C6F, version = 150)
public int sceKernelFreePartitionMemory_660(int uid) {
return Modules.SysMemUserForUserModule.sceKernelFreePartitionMemory(uid);
}
@HLEUnimplemented
@HLEFunction(nid = 0x1AB50974, version = 150)
public int sceKernelJointMemoryBlock(int id1, int id2) {
return 0;
}
@HLEFunction(nid = 0x22A114DC, version = 150)
public int sceKernelMemset32(TPointer destAddr, int data, int size) {
IMemoryWriter memoryWriter = MemoryWriter.getMemoryWriter(destAddr.getAddress(), size, 4);
for (int i = 0; i < size; i += 4) {
memoryWriter.writeNext(data);
}
memoryWriter.flush();
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xE860BE8F, version = 150)
public int sceKernelQueryMemoryBlockInfo(int id, @BufferInfo(lengthInfo=LengthInfo.fixedLength, length=56, usage=Usage.out) TPointer infoPtr) {
infoPtr.clear(56);
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xC90B0992, version = 150)
public int sceKernelGetUIDcontrolBlock(int id, TPointer32 controlBlockAddr) {
if (dummyControlBlock == null) {
dummyControlBlock = Modules.SysMemUserForUserModule.malloc(SysMemUserForUser.KERNEL_PARTITION_ID, "DummyControlBlock", SysMemUserForUser.PSP_SMEM_Low, 36, 0);
if (dummyControlBlock == null) {
return -1;
}
}
TPointer dummyControlBlockPtr = new TPointer(Memory.getInstance(), dummyControlBlock.addr);
dummyControlBlockPtr.clear(36);
dummyControlBlockPtr.setValue32(22, 0xFF); // SceSysmemUidCB.attr
controlBlockAddr.setValue(dummyControlBlockPtr.getAddress());
return 0;
}
}