Implemented sceKernelLoadModule()

Note that it wasn't tested because all the games I tested had other problems (already implemented modules, encrypted modules, using different functions etc).
But code looks good so it'd probably need few (no?) fixes.
This commit is contained in:
Arthur Blot 2012-11-04 19:01:20 +01:00
parent 6f391515a6
commit 9be8be6b7f
6 changed files with 177 additions and 100 deletions

View File

@ -77,6 +77,20 @@ bool ElfReader::LoadInto(u32 vaddr)
bRelocate = (header->e_type != ET_EXEC); bRelocate = (header->e_type != ET_EXEC);
entryPoint = header->e_entry; entryPoint = header->e_entry;
u32 totalSize = 0;
for (int i=0; i<header->e_phnum; i++)
{
Elf32_Phdr *p = segments + i;
if (p->p_type == PT_LOAD && p->p_vaddr + p->p_memsz > totalSize)
{
totalSize = p->p_vaddr + p->p_memsz;
}
}
if (vaddr)
vaddr = userMemory.AllocAt(vaddr, totalSize, "ELF");
else
vaddr = userMemory.Alloc(totalSize, false, "ELF");
if (bRelocate) if (bRelocate)
{ {
DEBUG_LOG(LOADER,"Relocatable module"); DEBUG_LOG(LOADER,"Relocatable module");
@ -109,8 +123,6 @@ bool ElfReader::LoadInto(u32 vaddr)
u32 srcSize = p->p_filesz; u32 srcSize = p->p_filesz;
u32 dstSize = p->p_memsz; u32 dstSize = p->p_memsz;
userMemory.AllocAt(writeAddr, dstSize, "ELF");
memcpy(dst, src, srcSize); memcpy(dst, src, srcSize);
if (srcSize < dstSize) if (srcSize < dstSize)
{ {

View File

@ -95,6 +95,15 @@ public:
} }
SectionID GetSectionByName(const char *name, int firstSection=0); //-1 for not found SectionID GetSectionByName(const char *name, int firstSection=0); //-1 for not found
u32 GetSegmentPaddr(int segment)
{
return segments[segment].p_paddr;
}
u32 GetSegmentOffset(int segment)
{
return segments[segment].p_offset;
}
bool DidRelocate() { bool DidRelocate() {
return bRelocate; return bRelocate;
} }

View File

@ -72,6 +72,10 @@ template<u32 func(int, u32)> void Wrap() {
RETURN(retval); RETURN(retval);
} }
template<u32 func(const char *, u32)> void Wrap() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
RETURN((u32)retval);
}
template<int func(const char *, u32)> void Wrap() { template<int func(const char *, u32)> void Wrap() {
int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
RETURN((u32)retval); RETURN((u32)retval);

View File

@ -28,6 +28,7 @@
#include "../MIPS/MIPSCodeUtils.h" #include "../MIPS/MIPSCodeUtils.h"
static std::vector<HLEModule> moduleDB; static std::vector<HLEModule> moduleDB;
static std::vector<Syscall> unresolvedSyscalls;
void HLEInit() void HLEInit()
{ {
@ -39,32 +40,6 @@ void HLEShutdown()
moduleDB.clear(); moduleDB.clear();
} }
/*
//unused
struct PSPHeader
{
char psp[4];
u32 version; //00080000
short whatever; //0101
char sometext[28];
short whatever2; //0102
u32 filesizedecrypted;
u32 filesize;
u32 unknownoffsets[3];
short whatever3[2]; //0x40 0x40
u32 whatever4[2]; //00
u32 whatever5; //1067008
u32 whatever6[2]; //00
u32 whatever7; //1067008
u32 whatever8; //2553296
u32 whatever9[8]; //0
u32 whatever10; //12
u32 encryptedStuff[12];
u32 filesizedecrypted2;
u32 whatever11;//0x80
u32 whatever12[6];
};*/
void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable) void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable)
{ {
HLEModule module = {name, numFunctions, funcTable}; HLEModule module = {name, numFunctions, funcTable};
@ -157,8 +132,36 @@ void WriteSyscall(const char *moduleName, u32 nib, u32 address)
Memory::Write_U32(MIPS_MAKE_NOP(), address+4); //patched out? Memory::Write_U32(MIPS_MAKE_NOP(), address+4); //patched out?
return; return;
} }
Memory::Write_U32(MIPS_MAKE_JR_RA(), address); // jr ra int modindex = GetModuleIndex(moduleName);
Memory::Write_U32(GetSyscallOp(moduleName, nib), address + 4); if (modindex != -1)
{
Memory::Write_U32(MIPS_MAKE_JR_RA(), address); // jr ra
Memory::Write_U32(GetSyscallOp(moduleName, nib), address + 4);
}
else
{
// Module inexistent.. for now; let's store the syscall for it to be resolved later
INFO_LOG(HLE,"Syscall (%s,%08x) unresolved, storing for later resolving", moduleName, nib);
Syscall sysc = {"", address, nib};
strncpy(sysc.moduleName, moduleName, 32);
sysc.moduleName[31] = '\0';
unresolvedSyscalls.push_back(sysc);
}
}
void ResolveSyscall(const char *moduleName, u32 nib, u32 address)
{
for (size_t i = 0; i < unresolvedSyscalls.size(); i++)
{
Syscall *sysc = &unresolvedSyscalls[i];
if (strncmp(sysc->moduleName, moduleName, 32) == 0 && sysc->nid == nib)
{
INFO_LOG(HLE,"Resolving %s/%08x",moduleName,nib);
// Note: doing that, we can't trace external module calls, so maybe something else should be done to debug more efficiently
Memory::Write_U32(MIPS_MAKE_JAL(address), sysc->symAddr);
Memory::Write_U32(MIPS_MAKE_NOP(), sysc->symAddr + 4);
}
}
} }
const char *GetFuncName(int moduleIndex, int func) const char *GetFuncName(int moduleIndex, int func)

View File

@ -40,6 +40,13 @@ struct HLEModule
const HLEFunction *funcTable; const HLEFunction *funcTable;
}; };
struct Syscall
{
char moduleName[32];
u32 symAddr;
u32 nid;
};
#define PARAM(n) currentMIPS->r[4+n] #define PARAM(n) currentMIPS->r[4+n]
#define RETURN(n) currentMIPS->r[2]=n #define RETURN(n) currentMIPS->r[2]=n
#define RETURN2(n) currentMIPS->r[3]=n #define RETURN2(n) currentMIPS->r[3]=n
@ -69,6 +76,7 @@ u32 GetNibByName(const char *module, const char *function);
u32 GetSyscallOp(const char *module, u32 nib); u32 GetSyscallOp(const char *module, u32 nib);
void WriteSyscall(const char *module, u32 nib, u32 address); void WriteSyscall(const char *module, u32 nib, u32 address);
void CallSyscall(u32 op); void CallSyscall(u32 op);
void ResolveSyscall(const char *moduleName, u32 nib, u32 address);
// Need to be able to save entire kernel state // Need to be able to save entire kernel state
int GetStateSize(); int GetStateSize();

View File

@ -105,15 +105,14 @@ struct SceKernelSMOption {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// STATE BEGIN // STATE BEGIN
static int numLoadedModules;
static SceUID mainModuleID; // hack static SceUID mainModuleID; // hack
// STATE END // STATE END
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, SceUID &id, std::string *error_string) Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *error_string)
{ {
Module *m = new Module; Module *module = new Module;
kernelObjects.Create(m); kernelObjects.Create(module);
u32 magic = *((u32*)ptr); u32 magic = *((u32*)ptr);
@ -158,17 +157,11 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, SceUID &id, std::
u32 __entrytableAddr; u32 __entrytableAddr;
}; };
SectionID entSection = reader.GetSectionByName(".lib.ent");
SectionID textSection = reader.GetSectionByName(".text"); SectionID textSection = reader.GetSectionByName(".text");
u32 sceResidentAddr = 0;
u32 moduleInfoAddr = 0;
u32 textStart = reader.GetSectionAddr(textSection); u32 textStart = reader.GetSectionAddr(textSection);
u32 textSize = reader.GetSectionSize(textSection); u32 textSize = reader.GetSectionSize(textSection);
SectionID sceResidentSection = reader.GetSectionByName(".rodata.sceResident");
SectionID sceModuleInfoSection = reader.GetSectionByName(".rodata.sceModuleInfo");
bool hasSymbols = false; bool hasSymbols = false;
bool dontadd = false; bool dontadd = false;
@ -186,28 +179,6 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, SceUID &id, std::
dontadd = true; dontadd = true;
} }
if (entSection != -1)
{
//libent *lib = (libent *)(Memory::GetPointer(reader.GetSectionAddr(entSection)));
//what's this for?
//lib->l1+=0;
}
sceResidentAddr = reader.GetSectionAddr(sceResidentSection);
moduleInfoAddr = reader.GetSectionAddr(sceModuleInfoSection);
struct PspResidentData
{
u32 l1; // unknown 0xd632acdb
u32 l2; // unknown 0xf01d73a7
u32 startAddress; // address of _start
u32 moduleInfoAddr; // address of sceModuleInfo struct
};
DEBUG_LOG(LOADER,"Resident data addr: %08x", sceResidentAddr);
//PspResidentData *resdata = (PspResidentData *)Memory::GetPointer(sceResidentAddr);
struct PspModuleInfo struct PspModuleInfo
{ {
// 0, 0, 1, 1 ? // 0, 0, 1, 1 ?
@ -222,23 +193,25 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, SceUID &id, std::
u32 libstubend; // ptr to end of .lib.stub section u32 libstubend; // ptr to end of .lib.stub section
}; };
PspModuleInfo *modinfo = (PspModuleInfo *)Memory::GetPointer(moduleInfoAddr); SectionID sceModuleInfoSection = reader.GetSectionByName(".rodata.sceModuleInfo");
m->gp_value = modinfo->gp; PspModuleInfo *modinfo;
strncpy(m->name, modinfo->name, 28); // TODO if (sceModuleInfoSection != -1)
modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetSectionAddr(sceModuleInfoSection));
else
modinfo = (PspModuleInfo *)reader.GetPtr(reader.GetSegmentPaddr(0) + reader.GetSegmentOffset(0));
module->gp_value = modinfo->gp;
strncpy(module->name, modinfo->name, 28);
DEBUG_LOG(LOADER,"Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent,modinfo->libstub); DEBUG_LOG(LOADER,"Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent,modinfo->libstub);
struct PspLibStubEntry struct PspLibStubEntry
{ {
// pointer to module name (will be in .rodata.sceResident section) u32 name;
u32 moduleNameSymbol; u16 version;
// mod version?? u16 flags;
unsigned short version; u16 size;
unsigned short val1; u16 numFuncs;
unsigned char val2; // 0x5
unsigned char val3;
// number of function symbols
unsigned short numFuncs;
// each symbol has an associated nid; nidData is a pointer // each symbol has an associated nid; nidData is a pointer
// (in .rodata.sceNid section) to an array of longs, one // (in .rodata.sceNid section) to an array of longs, one
// for each function, which identifies the function whose // for each function, which identifies the function whose
@ -252,8 +225,6 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, SceUID &id, std::
// should be filled in // should be filled in
u32 firstSymAddr; u32 firstSymAddr;
}; };
//sceDisplay at 5968-
int numModules = (modinfo->libstubend - modinfo->libstub)/sizeof(PspLibStubEntry); int numModules = (modinfo->libstubend - modinfo->libstub)/sizeof(PspLibStubEntry);
@ -265,9 +236,8 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, SceUID &id, std::
int numSyms=0; int numSyms=0;
for (int m=0; m<numModules; m++) for (int m=0; m<numModules; m++)
{ {
const char *modulename = (const char*)Memory::GetPointer(entry[m].moduleNameSymbol); const char *modulename = (const char*)Memory::GetPointer(entry[m].name);
u32 *nidDataPtr = (u32*)Memory::GetPointer(entry[m].nidData); u32 *nidDataPtr = (u32*)Memory::GetPointer(entry[m].nidData);
//u32 *stubs = (u32*)Memory::GetPointer(entry[m].firstSymAddr);
DEBUG_LOG(LOADER,"Importing Module %s, stubs at %08x",modulename,entry[m].firstSymAddr); DEBUG_LOG(LOADER,"Importing Module %s, stubs at %08x",modulename,entry[m].firstSymAddr);
@ -288,9 +258,58 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, SceUID &id, std::
DEBUG_LOG(LOADER,"-------------------------------------------------------------"); DEBUG_LOG(LOADER,"-------------------------------------------------------------");
} }
m->entry_addr = reader.GetEntryPoint(); struct PspLibEntEntry
{
u32 name; /* ent's name (module name) address */
u16 version;
u16 flags;
u8 size;
u8 vcount;
u16 fcount;
u32 resident;
};
return m; int numEnts = (modinfo->libentend - modinfo->libent)/sizeof(PspLibEntEntry);
PspLibEntEntry *ent = (PspLibEntEntry *)Memory::GetPointer(modinfo->libent);
for (int m=0; m<numEnts; m++)
{
const char *name;
if (ent->size == 0)
{
continue;
}
if (ent->name == 0)
{
// ?
name = module->name;
}
else
{
name = (const char*)Memory::GetPointer(ent->name);
}
INFO_LOG(HLE,"Exporting ent %d named %s, %d funcs, %d vars, resident %08x", m, name, ent->fcount, ent->vcount, ent->resident);
u32 *residentPtr = (u32*)Memory::GetPointer(ent[m].resident);
for (u32 j = 0; j < ent[m].fcount; j++)
{
u32 nid = residentPtr[j];
u32 exportAddr = residentPtr[ent->fcount + ent->vcount + j];
ResolveSyscall(name, nid, exportAddr);
}
if (ent->size > 4)
{
ent = (PspLibEntEntry*)((u8*)ent + ent->size * 4);
}
else
{
ent++;
}
}
module->entry_addr = reader.GetEntryPoint();
return module;
} }
bool __KernelLoadPBP(const char *filename, std::string *error_string) bool __KernelLoadPBP(const char *filename, std::string *error_string)
@ -331,8 +350,7 @@ bool __KernelLoadPBP(const char *filename, std::string *error_string)
{ {
u8 *temp = new u8[1024*1024*8]; u8 *temp = new u8[1024*1024*8];
in.read((char*)temp, 1024*1024*8); in.read((char*)temp, 1024*1024*8);
SceUID id; Module *m = __KernelLoadELFFromPtr(temp, PSP_GetDefaultLoadAddress(), error_string);
Module *m = __KernelLoadELFFromPtr(temp, PSP_GetDefaultLoadAddress(), id, error_string);
if (!m) if (!m)
return false; return false;
mipsr4k.pc = m->entry_addr; mipsr4k.pc = m->entry_addr;
@ -343,7 +361,7 @@ bool __KernelLoadPBP(const char *filename, std::string *error_string)
} }
Module *__KernelLoadModule(u8 *fileptr, SceUID &id, SceKernelLMOption *options, std::string *error_string) Module *__KernelLoadModule(u8 *fileptr, SceKernelLMOption *options, std::string *error_string)
{ {
Module *m = 0; Module *m = 0;
// Check for PBP // Check for PBP
@ -360,11 +378,11 @@ Module *__KernelLoadModule(u8 *fileptr, SceUID &id, SceKernelLMOption *options,
offsets[0] = offset0; offsets[0] = offset0;
for (int i = 1; i < numfiles; i++) for (int i = 1; i < numfiles; i++)
memcpy(&offsets[i], fileptr + 12 + 4*i, 4); memcpy(&offsets[i], fileptr + 12 + 4*i, 4);
m = __KernelLoadELFFromPtr(fileptr + offsets[5], PSP_GetDefaultLoadAddress(), id, error_string); m = __KernelLoadELFFromPtr(fileptr + offsets[5], PSP_GetDefaultLoadAddress(), error_string);
} }
else else
{ {
m = __KernelLoadELFFromPtr(fileptr, PSP_GetDefaultLoadAddress(), id, error_string); m = __KernelLoadELFFromPtr(fileptr, PSP_GetDefaultLoadAddress(), error_string);
} }
return m; return m;
@ -410,8 +428,7 @@ bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std::
pspFileSystem.ReadFile(handle, temp, (size_t)size); pspFileSystem.ReadFile(handle, temp, (size_t)size);
SceUID moduleID; Module *m = __KernelLoadModule(temp, 0, error_string);
Module *m = __KernelLoadModule(temp, moduleID, 0, error_string);
if (!m) { if (!m) {
ERROR_LOG(LOADER, "Failed to load module %s", filename); ERROR_LOG(LOADER, "Failed to load module %s", filename);
@ -454,10 +471,33 @@ void sceKernelLoadExec()
ERROR_LOG(HLE, "sceKernelLoadExec failed: %s", error_string.c_str()); ERROR_LOG(HLE, "sceKernelLoadExec failed: %s", error_string.c_str());
} }
void sceKernelLoadModule() u32 sceKernelLoadModule(const char *name, u32 flags)
{ {
const char *name = Memory::GetCharPointer(PARAM(0)); PSPFileInfo info = pspFileSystem.GetFileInfo(name);
u32 flags = PARAM(1); std::string error_string;
s64 size = (s64)info.size;
if (!size)
{
ERROR_LOG(LOADER, "Module file is size 0: %s", name);
return false;
}
u32 handle = pspFileSystem.OpenFile(name, FILEACCESS_READ);
u8 *temp = new u8[(int)size];
pspFileSystem.ReadFile(handle, temp, (size_t)size);
Module *m = __KernelLoadELFFromPtr(temp, 0, &error_string);
if (!m) {
ERROR_LOG(LOADER, "Failed to load module %s", name);
return false;
}
delete [] temp;
pspFileSystem.CloseFile(handle);
if (PARAM(2)) if (PARAM(2))
{ {
SceKernelLMOption *lmoption= (SceKernelLMOption *)Memory::GetPointer(PARAM(2)); SceKernelLMOption *lmoption= (SceKernelLMOption *)Memory::GetPointer(PARAM(2));
@ -467,14 +507,15 @@ void sceKernelLoadModule()
//Else, actually do load it and resolve pointers! //Else, actually do load it and resolve pointers!
INFO_LOG(HLE,"%i=sceKernelLoadModule(name=%s,flag=%08x,%08x,%08x,%08x,%08x(...))", INFO_LOG(HLE,"%i=sceKernelLoadModule(name=%s,flag=%08x,%08x,%08x,%08x,%08x(...))",
numLoadedModules+1,name,flags, m->GetUID(),name,flags,
lmoption->size,lmoption->mpidtext,lmoption->mpiddata,lmoption->position); lmoption->size,lmoption->mpidtext,lmoption->mpiddata,lmoption->position);
} }
else else
{ {
ERROR_LOG(HLE,"%i=sceKernelLoadModule(name=%s,flag=%08x,(...))", numLoadedModules+1, name, flags); INFO_LOG(HLE,"%i=sceKernelLoadModule(name=%s,flag=%08x,(...))", m->GetUID(), name, flags);
} }
RETURN(++numLoadedModules);
return m->GetUID();
} }
void sceKernelStartModule() void sceKernelStartModule()
@ -528,18 +569,18 @@ u32 sceKernelFindModuleByName(u32)
const HLEFunction ModuleMgrForUser[] = const HLEFunction ModuleMgrForUser[] =
{ {
{0x977DE386,sceKernelLoadModule,"sceKernelLoadModule"}, {0x977DE386,&Wrap<sceKernelLoadModule>,"sceKernelLoadModule"},
{0xb7f46618,0,"sceKernelLoadModuleByID"}, {0xb7f46618,0,"sceKernelLoadModuleByID"},
{0x50F0C1EC,sceKernelStartModule,"sceKernelStartModule"}, {0x50F0C1EC,&Wrap<sceKernelStartModule>,"sceKernelStartModule"},
{0xD675EBB8,sceKernelExitGame,"sceKernelSelfStopUnloadModule"}, //HACK {0xD675EBB8,&Wrap<sceKernelExitGame>,"sceKernelSelfStopUnloadModule"}, //HACK
{0xd1ff982a,sceKernelStopModule,"sceKernelStopModule"}, {0xd1ff982a,&Wrap<sceKernelStopModule>,"sceKernelStopModule"},
{0x2e0911aa,sceKernelUnloadModule,"sceKernelUnloadModule"}, {0x2e0911aa,&Wrap<sceKernelUnloadModule>,"sceKernelUnloadModule"},
{0x710F61B5,0,"sceKernelLoadModuleMs"}, {0x710F61B5,0,"sceKernelLoadModuleMs"},
{0xF9275D98,0,"sceKernelLoadModuleBufferUsbWlan"}, ///??? {0xF9275D98,0,"sceKernelLoadModuleBufferUsbWlan"}, ///???
{0xCC1D3699,0,"sceKernelStopUnloadSelfModule"}, {0xCC1D3699,0,"sceKernelStopUnloadSelfModule"},
{0x748CBED9,0,"sceKernelQueryModuleInfo"}, {0x748CBED9,0,"sceKernelQueryModuleInfo"},
{0xd8b73127,sceKernelGetModuleIdByAddress, "sceKernelGetModuleIdByAddress"}, {0xd8b73127,&Wrap<sceKernelGetModuleIdByAddress>, "sceKernelGetModuleIdByAddress"},
{0xf0a26395,sceKernelGetModuleId, "sceKernelGetModuleId"}, {0xf0a26395,&Wrap<sceKernelGetModuleId>, "sceKernelGetModuleId"},
{0x8f2df740,0,"sceKernel_ModuleMgr_8f2df740"}, {0x8f2df740,0,"sceKernel_ModuleMgr_8f2df740"},
}; };