/*
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 java.util.LinkedList;
import java.util.List;
import jpcsp.Loader;
import jpcsp.Memory;
import jpcsp.NIDMapper;
import jpcsp.HLE.HLEModuleManager;
import jpcsp.HLE.Modules;
import jpcsp.HLE.kernel.managers.SceUidManager;
import jpcsp.HLE.modules.SysMemUserForUser.SysMemInfo;
import jpcsp.format.DeferredStub;
import jpcsp.format.PSF;
import jpcsp.format.PSPModuleInfo;
import jpcsp.util.Utilities;
public class SceModule {
public static final int PSP_MODULE_VSH = 0x0800;
public static final int PSP_MODULE_KERNEL = 0x1000;
// PSP info
public int next; // should be handled by a manager
public short attribute;
public byte[] version = new byte[2];
public String modname; // 27 printable chars
public final byte terminal = (byte)0;
public int status; // 2 bytes for status + 2 bytes of padding
public int unk1;
public int modid;
public int usermod_thid;
public int memid;
public int mpidtext;
public int mpiddata;
public int ent_top;
public int ent_size; // we'll use bytes (instead of number of entries)
public int stub_top;
public int stub_size; // we'll use bytes (instead of number of entries)
public int module_start_func;
public int module_stop_func;
public int module_bootstart_func;
public int module_reboot_before_func;
public int module_reboot_phase_func;
public int entry_addr;
public int gp_value;
public int text_addr;
public int text_size;
public int data_size;
public int bss_size;
private List<SysMemInfo> allocatedMemory;
public int nsegment; // usually just 1 segment
public int[] segmentaddr = new int[4]; // static memory footprint of the module
public int[] segmentsize = new int[4]; // static memory footprint of the module
public int module_start_thread_priority;
public int module_start_thread_stacksize;
public int module_start_thread_attr;
public int module_stop_thread_priority;
public int module_stop_thread_stacksize;
public int module_stop_thread_attr;
public int module_reboot_before_thread_priority;
public int module_reboot_before_thread_stacksize;
public int module_reboot_before_thread_attr;
// internal info
public static final int size = 196;
public final int address;
public final boolean isFlashModule;
public boolean isLoaded;
public boolean isStarted;
public boolean isStopped;
private static SceModule previousModule; // The last module to be loaded, should be fixed up if that module gets unloaded
// loader stuff
public int fileFormat; // See Loader class for valid formats
public String pspfilename; // boot path, for thread argument
public PSF psf; // for xmb title, etc
// The space consumed by the program image
public int loadAddressLow, loadAddressHigh;
public int baseAddress; // should in theory be the same as loadAddressLow
// address/size pairs, used by the debugger/instruction counter
//public int[] textsection; // see text_addr/text_size
public int[] initsection;
public int[] finisection;
public int[] stubtextsection;
// deferred import resolving
public List<DeferredStub> unresolvedImports;
public int importFixupAttempts;
public List<DeferredStub> resolvedImports;
private List<String> moduleNames = new LinkedList<String>();
private static int sceModuleAddressOffset = 0x08400000; // reset this when we reset the emu
public static void ResetAllocator() {
sceModuleAddressOffset = 0x08400000;
}
public SceModule(boolean isFlashModule) {
this.isFlashModule = isFlashModule;
modid = SceUidManager.getNewUid("SceModule");
sceModuleAddressOffset -= (size + 256) & ~255;
address = sceModuleAddressOffset;
// Link SceModule structs together
if (previousModule != null) {
previousModule.next = address;
}
previousModule = this;
// Internal context
fileFormat = Loader.FORMAT_UNKNOWN;
//textsection = new int[2];
initsection = new int[2];
finisection = new int[2];
stubtextsection = new int[2];
unresolvedImports = new LinkedList<DeferredStub>();
importFixupAttempts = 0;
resolvedImports = new LinkedList<DeferredStub>();
allocatedMemory = new LinkedList<SysMemInfo>();
}
public void addModuleName(String moduleName) {
if (!moduleNames.contains(moduleName)) {
moduleNames.add(moduleName);
}
}
// State control methods.
public void load() {
isLoaded = true;
}
public void unload() {
// Unresolve all the stubs resolved by an entry in this module
if (!resolvedImports.isEmpty()) {
Memory mem = Memory.getInstance();
for (DeferredStub deferredStub : resolvedImports) {
deferredStub.unresolve(mem);
}
resolvedImports.clear();
}
// Remove all the NID's mapped from this module
NIDMapper.getInstance().removeModuleNids(modname);
for (String moduleName : moduleNames) {
NIDMapper.getInstance().removeModuleNids(moduleName);
}
isLoaded = false;
free();
}
public void start() {
isStarted = true;
}
public void stop() {
isStopped = true;
}
public boolean isModuleLoaded() {
return isLoaded;
}
public boolean isModuleStarted() {
return isStarted;
}
public boolean isModuleStopped() {
return isStopped;
}
/** For use when unloading modules. */
public void free() {
if (!allocatedMemory.isEmpty()) {
for (SysMemInfo sysMemInfo : allocatedMemory) {
// Overwrite the allocated memory so that its code can be invalidated
Memory.getInstance().memset(sysMemInfo.addr, (byte) -1, sysMemInfo.size);
Modules.SysMemUserForUserModule.free(sysMemInfo);
}
allocatedMemory.clear();
HLEModuleManager.getInstance().UnloadFlash0Module(this);
}
}
public void addAllocatedMemory(SysMemInfo sysMemInfo) {
if (sysMemInfo != null) {
allocatedMemory.add(sysMemInfo);
}
}
public void write(Memory mem, int address) {
mem.write32(address, next);
mem.write16(address + 4, attribute);
mem.write8(address + 6, version[0]);
mem.write8(address + 7, version[1]);
Utilities.writeStringNZ(mem, address + 8, 28, modname);
mem.write32(address + 36, status);
mem.write32(address + 40, unk1);
mem.write32(address + 44, modid);
mem.write32(address + 48, usermod_thid);
mem.write32(address + 52, memid);
mem.write32(address + 56, mpidtext);
mem.write32(address + 60, mpiddata);
mem.write32(address + 64, ent_top);
mem.write32(address + 68, ent_size);
mem.write32(address + 72, stub_top);
mem.write32(address + 76, stub_size);
mem.write32(address + 80, module_start_func);
mem.write32(address + 84, module_stop_func);
mem.write32(address + 88, module_bootstart_func);
mem.write32(address + 92, module_reboot_before_func);
mem.write32(address + 96, module_reboot_phase_func);
mem.write32(address + 100, entry_addr);
mem.write32(address + 104, gp_value);
mem.write32(address + 108, text_addr);
mem.write32(address + 112, text_size);
mem.write32(address + 116, data_size);
mem.write32(address + 120, bss_size);
mem.write32(address + 124, nsegment);
mem.write32(address + 128, segmentaddr[0]);
mem.write32(address + 132, segmentaddr[1]);
mem.write32(address + 136, segmentaddr[2]);
mem.write32(address + 140, segmentaddr[3]);
mem.write32(address + 144, segmentsize[0]);
mem.write32(address + 148, segmentsize[1]);
mem.write32(address + 152, segmentsize[2]);
mem.write32(address + 156, segmentsize[3]);
mem.write32(address + 160, module_start_thread_priority);
mem.write32(address + 164, module_start_thread_stacksize);
mem.write32(address + 168, module_start_thread_attr);
mem.write32(address + 172, module_stop_thread_priority);
mem.write32(address + 176, module_stop_thread_stacksize);
mem.write32(address + 180, module_stop_thread_attr);
mem.write32(address + 184, module_reboot_before_thread_priority);
mem.write32(address + 188, module_reboot_before_thread_stacksize);
mem.write32(address + 192, module_reboot_before_thread_attr);
}
public void read(Memory mem, int address) {
next = mem.read32(address);
attribute = (short)mem.read16(address + 4);
version[0] = (byte)mem.read8(address + 6);
version[1] = (byte)mem.read8(address + 7);
modname = Utilities.readStringNZ(mem, address + 8, 28);
status = mem.read32(address + 36);
unk1 = mem.read32(address + 40);
modid= mem.read32(address + 44);
usermod_thid = mem.read32(address + 48);
memid = mem.read32(address + 52);
mpidtext = mem.read32(address + 56);
mpiddata = mem.read32(address + 60);
ent_top = mem.read32(address + 64);
ent_size = mem.read32(address + 68);
stub_top = mem.read32(address + 72);
stub_size = mem.read32(address + 76);
module_start_func = mem.read32(address + 80);
module_stop_func = mem.read32(address + 84);
module_bootstart_func = mem.read32(address + 88);
module_reboot_before_func = mem.read32(address + 92);
module_reboot_phase_func = mem.read32(address + 96);
entry_addr = mem.read32(address + 100);
gp_value = mem.read32(address + 104);
text_addr = mem.read32(address + 108);
text_size = mem.read32(address + 112);
data_size = mem.read32(address + 116);
bss_size = mem.read32(address + 120);
nsegment = mem.read32(address + 124);
segmentaddr[0] = mem.read32(address + 128);
segmentaddr[1] = mem.read32(address + 132);
segmentaddr[2] = mem.read32(address + 136);
segmentaddr[3] = mem.read32(address + 140);
segmentsize[0] = mem.read32(address + 144);
segmentsize[1] = mem.read32(address + 148);
segmentsize[2] = mem.read32(address + 152);
segmentsize[3] = mem.read32(address + 156);
module_start_thread_priority = mem.read32(address + 160);
module_start_thread_stacksize = mem.read32(address + 164);
module_start_thread_attr = mem.read32(address + 168);
module_stop_thread_priority = mem.read32(address + 172);
module_stop_thread_stacksize = mem.read32(address + 176);
module_stop_thread_attr = mem.read32(address + 180);
module_reboot_before_thread_priority = mem.read32(address + 184);
module_reboot_before_thread_stacksize = mem.read32(address + 188);
module_reboot_before_thread_attr = mem.read32(address + 192);
}
/** initialise ourself from a PSPModuleInfo object.
* PSPModuleInfo object comes from the loader/ELF. */
public void copy(PSPModuleInfo moduleInfo) {
attribute = (short)(moduleInfo.getM_attr() & 0xFFFF);
version[0] = (byte)( moduleInfo.getM_version() & 0xFF);
version[1] = (byte)((moduleInfo.getM_version() >> 8) & 0xFF);
modname = moduleInfo.getM_namez();
gp_value = (int)(moduleInfo.getM_gp() & 0xFFFFFFFFL);
ent_top = (int)moduleInfo.getM_exports();
ent_size = (int)moduleInfo.getM_exp_end() - ent_top;
stub_top = (int)moduleInfo.getM_imports();
stub_size = (int)moduleInfo.getM_imp_end() - stub_top;
}
@Override
public String toString() {
return String.format("SceModule '%s'", modname);
}
}