/*
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.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Set;
import org.apache.log4j.Logger;
import jpcsp.HLE.BufferInfo;
import jpcsp.HLE.CanBeNull;
import jpcsp.HLE.HLEFunction;
import jpcsp.HLE.HLELogging;
import jpcsp.HLE.HLEModule;
import jpcsp.HLE.Modules;
import jpcsp.HLE.PspString;
import jpcsp.HLE.TPointer;
import jpcsp.HLE.TPointer32;
import jpcsp.HLE.BufferInfo.Usage;
import jpcsp.HLE.VFS.IVirtualFile;
import jpcsp.HLE.VFS.IVirtualFileSystem;
import jpcsp.HLE.kernel.Managers;
import jpcsp.HLE.kernel.types.SceKernelErrors;
import jpcsp.HLE.kernel.types.SceKernelLMOption;
import jpcsp.HLE.kernel.types.SceModule;
import jpcsp.HLE.modules.ModuleMgrForUser.LoadModuleContext;
import jpcsp.HLE.modules.SysMemUserForUser.SysMemInfo;
import jpcsp.util.Utilities;
public class ModuleMgrForKernel extends HLEModule {
public static Logger log = Modules.getLogger("ModuleMgrForKernel");
private Set<String> modulesWithMemoryAllocated;
@Override
public void start() {
modulesWithMemoryAllocated = new HashSet<>();
super.start();
}
public boolean isMemoryAllocatedForModule(String moduleName) {
if (modulesWithMemoryAllocated == null) {
return false;
}
return modulesWithMemoryAllocated.contains(moduleName);
}
@HLEFunction(nid = 0xBA889C07, version = 150)
public int sceKernelLoadModuleBuffer(TPointer buffer, int bufSize, int flags, @CanBeNull TPointer optionAddr) {
SceKernelLMOption lmOption = null;
if (optionAddr.isNotNull()) {
lmOption = new SceKernelLMOption();
lmOption.read(optionAddr);
if (log.isInfoEnabled()) {
log.info(String.format("sceKernelLoadModuleBuffer options: %s", lmOption));
}
}
LoadModuleContext loadModuleContext = new LoadModuleContext();
loadModuleContext.fileName = buffer.toString();
loadModuleContext.flags = flags;
loadModuleContext.buffer = buffer.getAddress();
loadModuleContext.bufferSize = bufSize;
loadModuleContext.lmOption = lmOption;
loadModuleContext.needModuleInfo = true;
loadModuleContext.allocMem = true;
return Modules.ModuleMgrForUserModule.hleKernelLoadModule(loadModuleContext);
}
/**
* Load a module with the VSH apitype.
*
* @param path The path to the module to load.
* @param flags Unused, always 0 .
* @param optionAddr Pointer to a mod_param_t structure. Can be NULL.
* @return
*/
@HLELogging(level = "info")
@HLEFunction(nid = 0xD5DDAB1F, version = 150)
public int sceKernelLoadModuleVSH(PspString path, int flags, @CanBeNull TPointer optionAddr) {
SceKernelLMOption lmOption = null;
if (optionAddr.isNotNull()) {
lmOption = new SceKernelLMOption();
lmOption.read(optionAddr);
if (log.isInfoEnabled()) {
log.info(String.format("sceKernelLoadModuleVSH options: %s", lmOption));
}
}
LoadModuleContext loadModuleContext = new LoadModuleContext();
loadModuleContext.fileName = path.getString();
loadModuleContext.flags = flags;
loadModuleContext.lmOption = lmOption;
loadModuleContext.needModuleInfo = true;
loadModuleContext.allocMem = true;
return Modules.ModuleMgrForUserModule.hleKernelLoadModule(loadModuleContext);
}
@HLEFunction(nid = 0xD86DD11B, version = 150)
public int sceKernelSearchModuleByName(PspString name) {
SceModule module = Managers.modules.getModuleByName(name.getString());
if (module == null) {
return SceKernelErrors.ERROR_KERNEL_UNKNOWN_MODULE;
}
return module.modid;
}
@HLEFunction(nid = 0x939E4270, version = 150, checkInsideInterrupt = true)
public int sceKernelLoadModule_660(PspString path, int flags, @CanBeNull TPointer optionAddr) {
return Modules.ModuleMgrForUserModule.sceKernelLoadModule(path, flags, optionAddr);
}
@HLEFunction(nid = 0x387E3CA9, version = 150, checkInsideInterrupt = true)
public int sceKernelUnloadModule_660(int uid) {
return Modules.ModuleMgrForUserModule.sceKernelUnloadModule(uid);
}
@HLEFunction(nid = 0x3FF74DF1, version = 150, checkInsideInterrupt = true)
public int sceKernelStartModule_660(int uid, int argSize, @CanBeNull TPointer argp, @CanBeNull TPointer32 statusAddr, @CanBeNull TPointer optionAddr) {
return Modules.ModuleMgrForUserModule.sceKernelStartModule(uid, argSize, argp, statusAddr, optionAddr);
}
@HLEFunction(nid = 0xE5D6087B, version = 150, checkInsideInterrupt = true)
public int sceKernelStopModule_660(int uid, int argSize, @CanBeNull TPointer argp, @CanBeNull TPointer32 statusAddr, @CanBeNull TPointer optionAddr) {
return Modules.ModuleMgrForUserModule.sceKernelStopModule(uid, argSize, argp, statusAddr, optionAddr);
}
@HLEFunction(nid = 0xD4EE2D26, version = 150, checkInsideInterrupt = true)
public int sceKernelLoadModuleToBlock(PspString path, int blockId, @BufferInfo(usage=Usage.out) TPointer32 separatedBlockId, int unknown2, @CanBeNull TPointer optionAddr) {
SceKernelLMOption lmOption = null;
if (optionAddr.isNotNull()) {
lmOption = new SceKernelLMOption();
lmOption.read(optionAddr);
if (log.isInfoEnabled()) {
log.info(String.format("sceKernelLoadModuleToBlock options: %s", lmOption));
}
}
SysMemInfo sysMemInfo = Modules.SysMemUserForUserModule.getSysMemInfo(blockId);
if (sysMemInfo == null) {
return -1;
}
if (log.isDebugEnabled()) {
log.debug(String.format("sceKernelLoadModuleToBlock sysMemInfo=%s", sysMemInfo));
}
modulesWithMemoryAllocated.add(path.getString());
// If we cannot load the module file, return the same blockId
separatedBlockId.setValue(blockId);
StringBuilder localFileName = new StringBuilder();
IVirtualFileSystem vfs = Modules.IoFileMgrForUserModule.getVirtualFileSystem(path.getString(), localFileName);
if (vfs != null) {
IVirtualFile vFile = vfs.ioOpen(localFileName.toString(), IoFileMgrForUser.PSP_O_RDONLY, 0);
if (vFile != null) {
byte[] bytes = new byte[(int) vFile.length()];
int length = vFile.ioRead(bytes, 0, bytes.length);
ByteBuffer moduleBuffer = ByteBuffer.wrap(bytes, 0, length);
SceModule module = Modules.ModuleMgrForUserModule.getModuleInfo(path.getString(), moduleBuffer, sysMemInfo.partitionid, sysMemInfo.partitionid);
if (module != null) {
int size = Modules.ModuleMgrForUserModule.getModuleRequiredMemorySize(module);
if (log.isDebugEnabled()) {
log.debug(String.format("sceKernelLoadModuleToBlock module requiring 0x%X bytes", size));
}
// Aligned on 256 bytes boundary
size = Utilities.alignUp(size, 0xFF);
SysMemInfo separatedSysMemInfo = Modules.SysMemUserForUserModule.separateMemoryBlock(sysMemInfo, size);
// This is the new blockId after calling sceKernelSeparateMemoryBlock
separatedBlockId.setValue(separatedSysMemInfo.uid);
if (log.isDebugEnabled()) {
log.debug(String.format("sceKernelLoadModuleToBlock separatedSysMemInfo=%s", separatedSysMemInfo));
}
}
}
}
LoadModuleContext loadModuleContext = new LoadModuleContext();
loadModuleContext.fileName = path.getString();
loadModuleContext.lmOption = lmOption;
loadModuleContext.needModuleInfo = true;
loadModuleContext.allocMem = false;
loadModuleContext.baseAddr = sysMemInfo.addr;
loadModuleContext.basePartition = sysMemInfo.partitionid;
return Modules.ModuleMgrForUserModule.hleKernelLoadModule(loadModuleContext);
}
}