/*
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;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import jpcsp.AllegrexOpcodes;
import jpcsp.Emulator;
import jpcsp.Memory;
import jpcsp.NIDMapper;
import jpcsp.Allegrex.compiler.RuntimeContext;
import jpcsp.HLE.VFS.IVirtualFileSystem;
import jpcsp.HLE.kernel.Managers;
import jpcsp.HLE.kernel.types.SceIoStat;
import jpcsp.HLE.kernel.types.SceModule;
import jpcsp.HLE.modules.ThreadManForUser;
/**
* Manager for the HLE modules.
* It defines which modules are loaded by default and
* which modules are loaded explicitly from flash0 or from a PRX.
*
* @author fiveofhearts
* @author gid15
*/
@HLELogging
public class HLEModuleManager {
private static Logger log = Modules.log;
private static HLEModuleManager instance;
public static final int HLESyscallNid = -1;
private boolean modulesStarted = false;
private boolean startFromSyscall;
private NIDMapper nidMapper;
private HashMap<String, List<HLEModule>> flash0prxMap;
private Set<HLEModule> installedModules = new HashSet<HLEModule>();
private Map<Integer, HLEModuleFunction> syscallToFunction;
private Map<Integer, HLEModuleFunction> nidToFunction;
private Map<HLEModule, ModuleInfo> moduleInfos;
private HLELogging defaultHLEFunctionLogging;
/**
* List of PSP modules that can be loaded when they are available.
* They will then replace the HLE equivalent.
*/
private static final String[] moduleFileNamesToBeLoaded = {
"flash0:/kd/utility.prx"
};
/**
* List of modules that can be loaded
* - by default in all firmwares (or only from a given FirmwareVersion)
* - by sceKernelLoadModule/sceUtilityLoadModule from the flash0 or from the UMD (.prx)
*/
private enum ModuleInfo {
SysMemUserForUser(Modules.SysMemUserForUserModule),
SysMemForKernel(Modules.SysMemForKernelModule),
IoFileMgrForUser(Modules.IoFileMgrForUserModule),
ThreadManForUser(Modules.ThreadManForUserModule),
InterruptManager(Modules.InterruptManagerModule),
LoadExecForUser(Modules.LoadExecForUserModule),
LoadExecForKernel(Modules.LoadExecForKernelModule),
StdioForUser(Modules.StdioForUserModule),
StdioForKernel(Modules.StdioForKernelModule),
sceUmdUser(Modules.sceUmdUserModule),
scePower(Modules.scePowerModule),
sceUtility(Modules.sceUtilityModule),
UtilsForUser(Modules.UtilsForUserModule),
sceDisplay(Modules.sceDisplayModule),
sceGe_user(Modules.sceGe_userModule),
sceRtc(Modules.sceRtcModule),
KernelLibrary(Modules.Kernel_LibraryModule),
ModuleMgrForUser(Modules.ModuleMgrForUserModule),
LoadCoreForKernel(Modules.LoadCoreForKernelModule),
sceCtrl(Modules.sceCtrlModule),
sceAudio(Modules.sceAudioModule),
sceImpose(Modules.sceImposeModule),
sceSuspendForUser(Modules.sceSuspendForUserModule),
sceDmac(Modules.sceDmacModule),
sceHprm(Modules.sceHprmModule), // check if loaded by default
sceAtrac3plus(Modules.sceAtrac3plusModule, new String[] { "libatrac3plus", "PSP_AV_MODULE_ATRAC3PLUS", "PSP_MODULE_AV_ATRAC3PLUS", "sceATRAC3plus_Library" }, "flash0:/kd/libatrac3plus.prx"),
sceSasCore(Modules.sceSasCoreModule, new String[] { "sc_sascore", "PSP_AV_MODULE_SASCORE", "PSP_MODULE_AV_SASCORE", "sceSAScore" }, "flash0:/kd/sc_sascore.prx"),
sceMpeg(Modules.sceMpegModule, new String[] { "mpeg", "mpeg_vsh", "mpeg_vsh370", "PSP_AV_MODULE_MPEGBASE", "PSP_MODULE_AV_MPEGBASE", "sceMpeg_library" }, "flash0:/kd/mpeg.prx"),
sceMpegbase(Modules.sceMpegbaseModule, new String[] { "PSP_AV_MODULE_AVCODEC", "PSP_MODULE_AV_AVCODEC", "avcodec", "sceMpegbase_Driver" }, "flash0:/kd/avcodec.prx"),
sceFont(Modules.sceFontModule, new String[] { "libfont", "sceFont_Library" }),
scePsmfPlayer(Modules.scePsmfPlayerModule, new String[] { "libpsmfplayer", "psmf_jk", "scePsmfP_library" }),
scePsmf(Modules.scePsmfModule, new String[] { "psmf", "scePsmf_library" }),
sceMp3(Modules.sceMp3Module, new String[] { "PSP_AV_MODULE_MP3", "PSP_MODULE_AV_MP3", "LIBMP3" }),
sceDeflt(Modules.sceDefltModule, new String[] { "libdeflt" }),
sceWlan(Modules.sceWlanModule),
sceNet(Modules.sceNetModule, new String[] { "pspnet", "PSP_NET_MODULE_COMMON", "PSP_MODULE_NET_COMMON" }, "flash0:/kd/pspnet.prx"),
sceNetAdhoc(Modules.sceNetAdhocModule, new String[] { "pspnet_adhoc", "PSP_NET_MODULE_ADHOC", "PSP_MODULE_NET_ADHOC" }, "flash0:/kd/pspnet_adhoc.prx"),
sceNetAdhocctl(Modules.sceNetAdhocctlModule, new String[] { "pspnet_adhocctl", "PSP_NET_MODULE_ADHOC", "PSP_MODULE_NET_ADHOC" }, "flash0:/kd/pspnet_adhocctl.prx"),
sceNetAdhocDiscover(Modules.sceNetAdhocDiscoverModule, new String[] { "pspnet_adhoc_discover", "PSP_NET_MODULE_ADHOC", "PSP_MODULE_NET_ADHOC" }, "flash0:/kd/pspnet_adhoc_discover.prx"),
sceNetAdhocMatching(Modules.sceNetAdhocMatchingModule, new String[] { "pspnet_adhoc_matching", "PSP_NET_MODULE_ADHOC", "PSP_MODULE_NET_ADHOC" }, "flash0:/kd/pspnet_adhoc_matching.prx"),
sceNetAdhocTransInt(Modules.sceNetAdhocTransIntModule, new String[] { "pspnet_adhoc_transfer_int" }, "flash0:/kd/pspnet_adhoc_transfer_int.prx"),
sceNetAdhocAuth(Modules.sceNetAdhocAuthModule, new String[] { "pspnet_adhoc_auth", "sceNetAdhocAuth_Service" }, "flash0:/kd/pspnet_adhoc_auth.prx"),
sceNetAdhocDownload(Modules.sceNetAdhocDownloadModule, new String[] { "pspnet_adhoc_download" }, "flash0:/kd/pspnet_adhoc_download.prx"),
sceNetIfhandle(Modules.sceNetIfhandleModule, new String[] { "ifhandle", "PSP_NET_MODULE_COMMON", "PSP_MODULE_NET_COMMON", "sceNetIfhandle_Service" }, "flash0:/kd/ifhandle.prx"),
sceNetApctl(Modules.sceNetApctlModule, new String[] { "pspnet_apctl", "PSP_NET_MODULE_COMMON", "PSP_MODULE_NET_COMMON" }, "flash0:/kd/pspnet_apctl.prx"),
sceNetInet(Modules.sceNetInetModule, new String[] { "pspnet_inet", "PSP_NET_MODULE_INET", "PSP_MODULE_NET_INET" }, "flash0:/kd/pspnet_inet.prx"),
sceNetResolver(Modules.sceNetResolverModule, new String[] { "pspnet_resolver", "PSP_NET_MODULE_COMMON", "PSP_MODULE_NET_COMMON" }, "flash0:/kd/pspnet_resolver.prx"),
sceNetUpnp(Modules.sceNetUpnpModule, new String[] { "pspnet_upnp", "PSP_MODULE_NET_UPNP" }, "flash0:/kd/pspnet_upnp.prx"),
sceOpenPSID(Modules.sceOpenPSIDModule),
sceNp(Modules.sceNpModule, new String[] { "np", "PSP_MODULE_NP_COMMON" }, "flash0:/kd/np.prx"),
sceNpCore(Modules.sceNpCoreModule, new String[] { "np_core" }, "flash0:/kd/np_core.prx"),
sceNpAuth(Modules.sceNpAuthModule, new String[] { "np_auth", "PSP_MODULE_NP_COMMON" }, "flash0:/kd/np_auth.prx"),
sceNpService(Modules.sceNpServiceModule, new String[] { "np_service", "PSP_MODULE_NP_SERVICE" }, "flash0:/kd/np_service.prx"),
sceNpCommerce2(Modules.sceNpCommerce2Module, new String[] { "np_commerce2", "PSP_MODULE_NP_COMMERCE2" }, "flash0:/kd/np_commerce2.prx"),
sceNpCommerce2Store(Modules.sceNpCommerce2StoreModule, new String[] { "np_commerce2_store" }, "flash0:/kd/np_commerce2_store.prx"),
sceNpCommerce2RegCam(Modules.sceNpCommerce2RegCamModule, new String[] { "np_commerce2_regcam" }, "flash0:/kd/np_commerce2_regcam.prx"),
sceNpMatching2(Modules.sceNpMatching2Module, new String[] { "np_matching2", "PSP_MODULE_NP_MATCHING2" }, "flash0:/kd/np_matching2.prx"),
sceNpInstall(Modules.sceNpInstallModule, new String[] { "np_inst" }, "flash0:/kd/np_inst.prx"),
sceNpCamp(Modules.sceNpCampModule, new String[] { "np_campaign" }, "flash0:/kd/np_campaign.prx"),
scePspNpDrm_user(Modules.scePspNpDrm_userModule, new String[] { "PSP_MODULE_NP_DRM", "npdrm" }),
sceVaudio(Modules.sceVaudioModule, new String[] { "PSP_AV_MODULE_VAUDIO", "PSP_MODULE_AV_VAUDIO" }),
sceMp4(Modules.sceMp4Module, new String[] { "PSP_MODULE_AV_MP4", "mp4msv", "libmp4" }, "flash0:/kd/libmp4.prx"),
sceHttp(Modules.sceHttpModule, new String[] { "libhttp", "libhttp_rfc", "PSP_NET_MODULE_HTTP", "PSP_MODULE_NET_HTTP" }, "flash0:/kd/libhttp.prx"),
sceHttps(Modules.sceHttpsModule, new String[] { "libhttp", "libhttp_rfc", "PSP_NET_MODULE_HTTP", "PSP_MODULE_NET_HTTP" }, "flash0:/kd/libhttp.prx"),
sceHttpStorage(Modules.sceHttpStorageModule, new String[] { "http_storage" }, "flash0:/kd/http_storage.prx"),
sceSsl(Modules.sceSslModule, new String[] { "libssl", "PSP_NET_MODULE_SSL", "PSP_MODULE_NET_SSL" }, "flash0:/kd/libssl.prx"),
sceP3da(Modules.sceP3daModule),
sceGameUpdate(Modules.sceGameUpdateModule, new String[] { "libgameupdate" }),
sceUsbCam(Modules.sceUsbCamModule, new String[] { "PSP_USB_MODULE_CAM", "PSP_MODULE_USB_CAM", "usbcam" }),
sceJpeg(Modules.sceJpegModule, new String[] { "PSP_AV_MODULE_AVCODEC", "PSP_MODULE_AV_AVCODEC" }, "flash0:/kd/avcodec.prx"),
sceUsb(Modules.sceUsbModule),
sceHeap(Modules.sceHeapModule, new String[] { "libheap" }),
KDebugForKernel(Modules.KDebugForKernelModule),
sceCcc(Modules.sceCccModule, new String[] { "libccc" }),
scePauth(Modules.scePauthModule),
sceSfmt19937(Modules.sceSfmt19937Module),
sceMd5(Modules.sceMd5Module, new String[] { "libmd5" }),
sceParseUri(Modules.sceParseUriModule, new String[] { "libparse_uri", "libhttp_rfc", "PSP_NET_MODULE_HTTP", "PSP_MODULE_NET_HTTP", "PSP_MODULE_NET_PARSEURI" }),
sceUsbAcc(Modules.sceUsbAccModule, new String[] { "PSP_USB_MODULE_ACC", "USBAccBaseDriver" }),
sceMt19937(Modules.sceMt19937Module, new String[] { "libmt19937" }),
sceAac(Modules.sceAacModule, new String[] { "libaac", "PSP_AV_MODULE_AAC", "PSP_MODULE_AV_AAC" }),
sceFpu(Modules.sceFpuModule, new String[] { "libfpu" }),
sceUsbMic(Modules.sceUsbMicModule, new String[] { "usbmic", "PSP_USB_MODULE_MIC", "PSP_MODULE_USB_MIC", "USBCamMicDriver" }),
sceAudioRouting(Modules.sceAudioRoutingModule),
sceUsbGps(Modules.sceUsbGpsModule, new String[] { "PSP_USB_MODULE_GPS", "PSP_MODULE_USB_GPS", "usbgps" }),
sceAudiocodec(Modules.sceAudiocodecModule, new String[] { "PSP_AV_MODULE_AVCODEC", "PSP_MODULE_AV_AVCODEC", "avcodec", "sceAudiocodec_Driver" }, "flash0:/kd/avcodec.prx"),
sceVideocodec(Modules.sceVideocodecModule, new String[] { "PSP_AV_MODULE_AVCODEC", "PSP_MODULE_AV_AVCODEC", "avcodec", "sceVideocodec_Driver" }, "flash0:/kd/avcodec.prx"),
sceAdler(Modules.sceAdlerModule, new String[] { "libadler" }),
sceSha1(Modules.sceSha1Module, new String[] { "libsha1" }),
sceSha256(Modules.sceSha256Module, new String[] { "libsha256" }),
sceMeCore(Modules.sceMeCoreModule),
sceMeBoot(Modules.sceMeBootModule),
KUBridge(Modules.KUBridgeModule),
SysclibForKernel(Modules.SysclibForKernelModule),
semaphore(Modules.semaphoreModule),
ModuleMgrForKernel(Modules.ModuleMgrForKernelModule),
sceReg(Modules.sceRegModule),
sceDve(Modules.sceDveModule),
sceSysEventForKernel(Modules.sceSysEventForKernelModule),
sceChkreg(Modules.sceChkregModule),
sceMsAudio_Service(Modules.sceMsAudio_ServiceModule),
sceMePower(Modules.sceMePowerModule),
sceResmgr(Modules.sceResmgrModule),
UtilsForKernel(Modules.UtilsForKernelModule),
sceLibUpdateDL(Modules.sceLibUpdateDLModule, new String[] { "libupdown" }),
sceParseHttp(Modules.sceParseHttpModule, new String[] { "libparse_http", "PSP_MODULE_NET_PARSEHTTP" }, "flash0:/kd/libparse_http.prx"),
sceMgr_driver(Modules.sceMgr_driverModule),
sceChnnlsv(Modules.sceChnnlsvModule, new String[] { "chnnlsv" }),
sceUsbstor(Modules.sceUsbstorModule),
sceIdStorage(Modules.sceIdStorageModule),
sceCertLoader(Modules.sceCertLoaderModule, new String[] { "cert_loader", "PSP_MODULE_NET_SSL" }, "flash0:/kd/cert_loader.prx"),
sceDNAS(Modules.sceDNASModule, new String[] { "libdnas" }),
sceDNASCore(Modules.sceDNASCoreModule, new String[] { "libdnas_core" }),
sceMcctrl(Modules.sceMcctrlModule, new String[] { "mcctrl" }),
sceNetStun(Modules.sceNetStunModule),
sceMeMemory(Modules.sceMeMemoryModule),
sceMeVideo(Modules.sceMeVideoModule),
sceMeAudio(Modules.sceMeAudioModule),
InitForKernel(Modules.InitForKernelModule),
sceMemab(Modules.sceMemabModule, new String[] { "memab", "sceMemab" }),
DmacManForKernel(Modules.DmacManForKernelModule),
sceSyscon(Modules.sceSysconModule),
sceLed(Modules.sceLedModule),
sceSysreg(Modules.sceSysregModule);
private HLEModule module;
private boolean loadedByDefault;
private String[] names;
private String prxFileName;
// Module loaded by default in all Firmware versions
ModuleInfo(HLEModule module) {
this.module = module;
loadedByDefault = true;
names = null;
}
// Module only loaded as a PRX, under different names
ModuleInfo(HLEModule module, String[] prxNames) {
this.module = module;
loadedByDefault = false;
this.names = prxNames;
}
// Module only loaded as a PRX, under different names
ModuleInfo(HLEModule module, String[] prxNames, String prxFileName) {
this.module = module;
loadedByDefault = false;
this.names = prxNames;
this.prxFileName = prxFileName;
}
public HLEModule getModule() {
return module;
}
public String[] getNames() {
return names;
}
public boolean isLoadedByDefault() {
return loadedByDefault;
}
public String getPrxFileName() {
return prxFileName;
}
};
public static HLEModuleManager getInstance() {
if (instance == null) {
instance = new HLEModuleManager();
}
return instance;
}
private HLEModuleManager() {
defaultHLEFunctionLogging = HLEModuleManager.class.getAnnotation(HLELogging.class);
nidMapper = NIDMapper.getInstance();
syscallToFunction = new HashMap<>();
nidToFunction = new HashMap<>();
}
/** (String)"2.71" to (int)271 */
public static int psfFirmwareVersionToInt(String firmwareVersion) {
int version = Emulator.getInstance().getFirmwareVersion();
if (firmwareVersion != null) {
// Some games have firmwareVersion = "5.00?", keep only the digits
while (!Character.isDigit(firmwareVersion.charAt(firmwareVersion.length() - 1))) {
firmwareVersion = firmwareVersion.substring(0, firmwareVersion.length() - 1);
}
version = (int)(Float.parseFloat(firmwareVersion) * 100);
// We started implementing stuff under 150 even if it existed in 100
if (version < 150) {
version = 150;
}
}
return version;
}
public void init() {
installedModules.clear();
installDefaultModules();
initialiseFlash0PRXMap();
}
/**
* Install the modules that are loaded by default on the current firmware version.
*/
private void installDefaultModules() {
if (log.isDebugEnabled()) {
log.debug(String.format("Loading default HLE modules"));
}
for (ModuleInfo defaultModule : ModuleInfo.values()) {
if (defaultModule.isLoadedByDefault()) {
installModuleWithAnnotations(defaultModule.getModule());
} else {
// This module is not loaded by default on this firmware version.
// Install and Uninstall the module to register the module syscalls
// so that the loader can still resolve the imports for this module.
installModuleWithAnnotations(defaultModule.getModule());
uninstallModuleWithAnnotations(defaultModule.getModule());
}
}
}
private void addToFlash0PRXMap(String prxName, HLEModule module) {
prxName = prxName.toLowerCase();
if (!flash0prxMap.containsKey(prxName)) {
flash0prxMap.put(prxName, new LinkedList<HLEModule>());
}
List<HLEModule> modules = flash0prxMap.get(prxName);
modules.add(module);
}
// Add modules in flash (or on UMD) that aren't loaded by default on this firmwareVersion
private void initialiseFlash0PRXMap() {
flash0prxMap = new HashMap<String, List<HLEModule>>();
moduleInfos = new HashMap<HLEModule, ModuleInfo>();
for (ModuleInfo moduleInfo : ModuleInfo.values()) {
HLEModule hleModule = moduleInfo.getModule();
moduleInfos.put(hleModule, moduleInfo);
if (!moduleInfo.isLoadedByDefault()) {
String[] names = moduleInfo.getNames();
for (int i = 0; names != null && i < names.length; i++) {
addToFlash0PRXMap(names[i], hleModule);
}
}
}
}
public boolean hasFlash0Module(String prxname) {
if (prxname == null) {
return false;
}
return flash0prxMap.containsKey(prxname.toLowerCase());
}
public String getModulePrxFileName(String name) {
if (name != null) {
List<HLEModule> modules = flash0prxMap.get(name.toLowerCase());
if (modules != null) {
for (HLEModule module : modules) {
ModuleInfo moduleInfo = moduleInfos.get(module);
if (moduleInfo != null) {
return moduleInfo.getPrxFileName();
}
}
}
}
return null;
}
/** @return the UID assigned to the module or negative on error
* TODO need to figure out how the uids work when 1 prx contains several modules. */
public int LoadFlash0Module(String name) {
if (name != null) {
List<HLEModule> modules = flash0prxMap.get(name.toLowerCase());
if (modules != null) {
for (HLEModule module : modules) {
installModuleWithAnnotations(module);
}
}
}
SceModule fakeModule = new SceModule(true);
fakeModule.modname = name;
fakeModule.write(Memory.getInstance(), fakeModule.address);
Managers.modules.addModule(fakeModule);
return fakeModule.modid;
}
public void UnloadFlash0Module(SceModule sceModule) {
if (sceModule == null) {
return;
}
if (sceModule.modname != null) {
List<HLEModule> prx = flash0prxMap.get(sceModule.modname.toLowerCase());
if (prx != null) {
for (HLEModule module : prx) {
uninstallModuleWithAnnotations(module);
}
}
}
// TODO terminate delete all threads that belong to this module
sceModule.free();
Managers.modules.removeModule(sceModule.modid);
if (!sceModule.isFlashModule) {
// Invalidate the compiled code from the unloaded module
RuntimeContext.invalidateAll();
}
}
public void addFunction(int nid, HLEModuleFunction func) {
int syscallCode;
if (nid == HLESyscallNid) {
syscallCode = nidMapper.getNewSyscallNumber();
} else {
if (!nidMapper.addHLENid(nid, func.getFunctionName(), func.getModuleName(), func.getFirmwareVersion())) {
log.error(String.format("Tried to register a second handler for NID 0x%08X called %s", nid, func.getFunctionName()));
}
nidToFunction.put(nid, func);
syscallCode = nidMapper.getSyscallByNid(nid, func.getModuleName());
}
if (syscallCode >= 0) {
func.setSyscallCode(syscallCode);
syscallToFunction.put(syscallCode, func);
}
}
public HLEModuleFunction getFunctionFromSyscallCode(int syscallCode) {
return syscallToFunction.get(syscallCode);
}
public HLEModuleFunction getFunctionFromAddress(int address) {
int nid = nidMapper.getNidByAddress(address);
if (nid == 0) {
// Verify if this not the address of a stub call:
// J realAddress
// NOP
Memory mem = Memory.getInstance();
if ((mem.read32(address) >>> 26) == AllegrexOpcodes.J) {
if (mem.read32(address + 4) == ThreadManForUser.NOP()) {
int jumpAddress = (mem.read32(address) & 0x03FFFFFF) << 2;
nid = nidMapper.getNidByAddress(jumpAddress);
}
}
}
if (nid == 0) {
return null;
}
HLEModuleFunction func = nidToFunction.get(nid);
return func;
}
public void removeFunction(HLEModuleFunction func) {
nidMapper.unloadNid(func.getNid());
}
public void startModules(boolean startFromSyscall) {
if (modulesStarted) {
return;
}
this.startFromSyscall = startFromSyscall;
for (ModuleInfo defaultModule : ModuleInfo.values()) {
if (defaultModule.module.isStarted()) {
if (log.isDebugEnabled()) {
log.debug(String.format("Module %s already started", defaultModule.module.getName()));
}
} else {
if (log.isDebugEnabled()) {
log.debug(String.format("Starting module %s", defaultModule.module.getName()));
}
defaultModule.module.start();
if (log.isDebugEnabled()) {
log.debug(String.format("Started module %s", defaultModule.module.getName()));
}
}
}
this.startFromSyscall = false;
modulesStarted = true;
}
public void stopModules() {
if (!modulesStarted) {
return;
}
for (ModuleInfo defaultModule : ModuleInfo.values()) {
defaultModule.module.stop();
}
modulesStarted = false;
}
public boolean isStartFromSyscall() {
return startFromSyscall;
}
private void installFunctionWithAnnotations(HLEFunction hleFunction, Method method, HLEModule hleModule) {
HLEUnimplemented hleUnimplemented = method.getAnnotation(HLEUnimplemented.class);
HLELogging hleLogging = method.getAnnotation(HLELogging.class);
// Take the module default logging if no HLELogging has been
// defined at the function level and if the function is not
// unimplemented (which will produce it's own logging).
if (hleLogging == null) {
if (hleUnimplemented != null) {
// Take the logging level of the HLEUnimplemented class
// as default value for unimplemented functions
hleLogging = HLEUnimplemented.class.getAnnotation(HLELogging.class);
} else {
HLELogging hleModuleLogging = method.getDeclaringClass().getAnnotation(HLELogging.class);
if (hleModuleLogging != null) {
// Take the module default logging
hleLogging = hleModuleLogging;
} else {
hleLogging = defaultHLEFunctionLogging;
}
}
}
String moduleName = hleFunction.moduleName();
String functionName = hleFunction.functionName();
if (moduleName.length() == 0) {
moduleName = hleModule.getName();
}
if (functionName.length() == 0) {
functionName = method.getName();
}
HLEModuleFunction hleModuleFunction = new HLEModuleFunction(moduleName, functionName, hleModule, method, hleFunction.checkInsideInterrupt(), hleFunction.checkDispatchThreadEnabled(), hleFunction.stackUsage(), hleFunction.version());
if (hleUnimplemented != null) {
hleModuleFunction.setUnimplemented(true);
}
if (hleLogging != null) {
hleModuleFunction.setLoggingLevel(hleLogging.level());
}
hleModule.installedHLEModuleFunctions.put(functionName, hleModuleFunction);
addFunction(hleFunction.nid(), hleModuleFunction);
}
/**
* Iterates over an object fields searching for HLEFunction annotations and install them.
*
* @param hleModule
*/
public void installModuleWithAnnotations(HLEModule hleModule) {
if (installedModules.contains(hleModule)) {
return;
}
try {
for (Method method : hleModule.getClass().getMethods()) {
HLEFunction hleFunction = method.getAnnotation(HLEFunction.class);
if (hleFunction != null) {
installFunctionWithAnnotations(hleFunction, method, hleModule);
}
}
} catch (Exception e) {
log.error("installModuleWithAnnotations", e);
}
installedModules.add(hleModule);
hleModule.load();
}
/**
* Same as installModuleWithAnnotations but uninstalling.
*
* @param hleModule
*/
public void uninstallModuleWithAnnotations(HLEModule hleModule) {
try {
for (HLEModuleFunction hleModuleFunction : hleModule.installedHLEModuleFunctions.values()) {
this.removeFunction(hleModuleFunction);
}
} catch (Exception e) {
log.error("uninstallModuleWithAnnotations", e);
}
installedModules.remove(hleModule);
hleModule.unload();
}
public void loadAvailableFlash0Modules() {
List<String> availableModuleFileNames = new LinkedList<>();
for (String moduleFileName : moduleFileNamesToBeLoaded) {
StringBuilder localFileName = new StringBuilder();
IVirtualFileSystem vfs = Modules.IoFileMgrForUserModule.getVirtualFileSystem(moduleFileName, localFileName);
if (vfs != null && vfs.ioGetstat(localFileName.toString(), new SceIoStat()) == 0) {
// The module is available, load it
availableModuleFileNames.add(moduleFileName);
}
}
if (availableModuleFileNames.isEmpty()) {
// No module available, do nothing
return;
}
// These 2 HLE modules need to be started in order
// to be able to load and start the available modules.
Modules.ModuleMgrForUserModule.start();
Modules.ThreadManForUserModule.start();
int startPriority = 0x10;
for (String moduleFileName : availableModuleFileNames) {
if (log.isInfoEnabled()) {
log.info(String.format("Loading and starting the module '%s', it will replace the equivalent HLE functions", moduleFileName));
}
Modules.ModuleMgrForUserModule.hleKernelLoadAndStartModule(moduleFileName, startPriority++);
}
}
}