2012-11-01 16:19:01 +01:00
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
2012-11-04 23:01:49 +01:00
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 16:19:01 +01:00
// This program 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
# include <fstream>
2012-11-05 15:41:37 +01:00
# include <algorithm>
2012-11-01 16:19:01 +01:00
# include "HLE.h"
2013-03-25 00:07:30 +01:00
# include "Core/Reporting.h"
2012-11-05 12:02:09 +01:00
# include "Common/FileUtil.h"
2012-11-01 16:19:01 +01:00
# include "../Host.h"
2013-04-08 21:46:41 +02:00
# include "Core/MIPS/MIPS.h"
# include "Core/MIPS/MIPSAnalyst.h"
# include "Core/ELF/ElfReader.h"
# include "Core/ELF/PBPReader.h"
# include "Core/ELF/PrxDecrypter.h"
2012-11-01 16:19:01 +01:00
# include "../Debugger/SymbolMap.h"
# include "../FileSystems/FileSystem.h"
# include "../FileSystems/MetaFileSystem.h"
# include "../Util/BlockAllocator.h"
2013-04-08 21:46:41 +02:00
# include "Core/CoreTiming.h"
# include "Core/PSPLoaders.h"
# include "Core/System.h"
# include "Core/MemMap.h"
# include "Core/Debugger/SymbolMap.h"
2012-11-01 16:19:01 +01:00
# include "sceKernel.h"
# include "sceKernelModule.h"
# include "sceKernelThread.h"
# include "sceKernelMemory.h"
2013-01-02 00:36:34 +01:00
# include "sceIo.h"
2012-11-01 16:19:01 +01:00
enum {
PSP_THREAD_ATTR_USER = 0x80000000
} ;
2013-01-04 00:36:08 -08:00
enum {
// Function exports.
NID_MODULE_START = 0xD632ACDB ,
NID_MODULE_STOP = 0xCEE8593C ,
NID_MODULE_REBOOT_BEFORE = 0x2F064FA6 ,
NID_MODULE_REBOOT_PHASE = 0xADF12745 ,
NID_MODULE_BOOTSTART = 0xD3744BE0 ,
// Variable exports.
NID_MODULE_INFO = 0xF01D73A7 ,
NID_MODULE_START_THREAD_PARAMETER = 0x0F7C276C ,
NID_MODULE_STOP_THREAD_PARAMETER = 0xCF0CC697 ,
NID_MODULE_REBOOT_BEFORE_THREAD_PARAMETER = 0xF4F4299D ,
NID_MODULE_SDK_VERSION = 0x11B97506 ,
} ;
2012-11-05 12:02:09 +01:00
static const char * blacklistedModules [ ] = {
2012-11-05 18:03:02 +01:00
" sceATRAC3plus_Library " ,
" sceFont_Library " ,
2012-11-07 20:59:56 +01:00
" SceFont_Library " ,
2013-02-02 23:40:44 -08:00
" SceHttp_Library " ,
" sceMpeg_library " ,
2012-11-05 18:03:02 +01:00
" sceNetAdhocctl_Library " ,
" sceNetAdhocDownload_Library " ,
" sceNetAdhocMatching_Library " ,
2013-02-03 22:13:42 +01:00
" sceNetApDialogDummy_Library " ,
2012-11-05 18:03:02 +01:00
" sceNetAdhoc_Library " ,
" sceNetApctl_Library " ,
" sceNetInet_Library " ,
2013-02-02 23:40:44 -08:00
" sceNetResolver_Library " ,
2012-11-05 18:03:02 +01:00
" sceNet_Library " ,
2013-02-04 00:54:50 +01:00
" sceSsl_Module " ,
2012-11-05 12:02:09 +01:00
} ;
2012-11-17 14:20:04 +01:00
struct NativeModule {
u32 next ;
u16 attribute ;
u8 version [ 2 ] ;
char name [ 28 ] ;
u32 status ;
u32 unk1 ;
u32 usermod_thid ;
u32 memid ;
u32 mpidtext ;
u32 mpiddata ;
u32 ent_top ;
u32 ent_size ;
u32 stub_top ;
u32 stub_size ;
u32 module_start_func ;
u32 module_stop_func ;
u32 module_bootstart_func ;
u32 module_reboot_before_func ;
u32 module_reboot_phase_func ;
u32 entry_addr ;
u32 gp_value ;
u32 text_addr ;
u32 text_size ;
u32 data_size ;
u32 bss_size ;
u32 nsegment ;
u32 segmentaddr [ 4 ] ;
u32 segmentsize [ 4 ] ;
u32 module_start_thread_priority ;
u32 module_start_thread_stacksize ;
u32 module_start_thread_attr ;
u32 module_stop_thread_priority ;
u32 module_stop_thread_stacksize ;
u32 module_stop_thread_attr ;
u32 module_reboot_before_thread_priority ;
u32 module_reboot_before_thread_stacksize ;
u32 module_reboot_before_thread_attr ;
} ;
2013-01-05 19:43:51 +01:00
// by QueryModuleInfo
struct ModuleInfo {
u32 nsegment ;
u32 segmentaddr [ 4 ] ;
u32 segmentsize [ 4 ] ;
u32 entry_addr ;
u32 gp_value ;
u32 text_addr ;
u32 text_size ;
u32 data_size ;
u32 bss_size ;
u16 attribute ;
u8 version [ 2 ] ;
char name [ 28 ] ;
} ;
2012-11-17 14:20:04 +01:00
class Module : public KernelObject
2012-11-01 16:19:01 +01:00
{
2012-11-17 14:20:04 +01:00
public :
2013-01-02 00:36:34 +01:00
Module ( ) : memoryBlockAddr ( 0 ) , isFake ( false ) { }
2012-11-17 14:20:04 +01:00
~ Module ( ) {
if ( memoryBlockAddr ) {
userMemory . Free ( memoryBlockAddr ) ;
}
}
const char * GetName ( ) { return nm . name ; }
2012-11-01 16:19:01 +01:00
const char * GetTypeName ( ) { return " Module " ; }
void GetQuickInfo ( char * ptr , int size )
{
// ignore size
2013-01-03 16:13:08 +01:00
sprintf ( ptr , " %sname=%s gp=%08x entry=%08x " ,
isFake ? " faked " : " " ,
2012-11-17 14:20:04 +01:00
nm . name ,
nm . gp_value ,
nm . entry_addr ) ;
2012-11-01 16:19:01 +01:00
}
static u32 GetMissingErrorCode ( ) { return SCE_KERNEL_ERROR_UNKNOWN_MODULE ; }
2012-12-26 22:45:19 -08:00
int GetIDType ( ) const { return PPSSPP_KERNEL_TMID_Module ; }
virtual void DoState ( PointerWrap & p )
{
p . Do ( nm ) ;
p . Do ( memoryBlockAddr ) ;
2013-04-10 21:03:43 -07:00
p . Do ( memoryBlockSize ) ;
2012-12-26 22:45:19 -08:00
p . DoMarker ( " Module " ) ;
}
2012-11-01 16:19:01 +01:00
2012-11-17 14:20:04 +01:00
NativeModule nm ;
u32 memoryBlockAddr ;
2013-04-10 21:03:43 -07:00
u32 memoryBlockSize ;
2013-01-02 00:36:34 +01:00
bool isFake ;
2012-11-01 16:19:01 +01:00
} ;
2012-12-26 22:45:19 -08:00
KernelObject * __KernelModuleObject ( )
{
return new Module ;
}
2012-12-27 19:30:36 -08:00
class AfterModuleEntryCall : public Action {
public :
AfterModuleEntryCall ( ) { }
SceUID moduleID_ ;
u32 retValAddr ;
2013-01-06 10:54:33 -08:00
virtual void run ( MipsCall & call ) ;
2012-12-27 19:30:36 -08:00
virtual void DoState ( PointerWrap & p ) {
p . Do ( moduleID_ ) ;
p . Do ( retValAddr ) ;
2012-12-28 13:01:46 -08:00
p . DoMarker ( " AfterModuleEntryCall " ) ;
2012-12-27 19:30:36 -08:00
}
static Action * Create ( ) {
return new AfterModuleEntryCall ;
}
} ;
2013-01-06 10:54:33 -08:00
void AfterModuleEntryCall : : run ( MipsCall & call ) {
2012-12-27 19:30:36 -08:00
Memory : : Write_U32 ( retValAddr , currentMIPS - > r [ 2 ] ) ;
}
2012-11-01 16:19:01 +01:00
//////////////////////////////////////////////////////////////////////////
// MODULES
//////////////////////////////////////////////////////////////////////////
struct StartModuleInfo
{
u32 size ;
u32 mpidtext ;
u32 mpiddata ;
u32 threadpriority ;
u32 threadattributes ;
} ;
struct SceKernelLMOption {
SceSize size ;
SceUID mpidtext ;
SceUID mpiddata ;
unsigned int flags ;
char position ;
char access ;
char creserved [ 2 ] ;
} ;
struct SceKernelSMOption {
SceSize size ;
SceUID mpidstack ;
SceSize stacksize ;
int priority ;
unsigned int attribute ;
} ;
//////////////////////////////////////////////////////////////////////////
// STATE BEGIN
2012-12-27 19:30:36 -08:00
static int actionAfterModule ;
2012-11-01 16:19:01 +01:00
// STATE END
//////////////////////////////////////////////////////////////////////////
2012-12-27 19:30:36 -08:00
void __KernelModuleInit ( )
{
actionAfterModule = __KernelRegisterActionType ( AfterModuleEntryCall : : Create ) ;
}
2012-12-27 14:21:39 -08:00
void __KernelModuleDoState ( PointerWrap & p )
{
2012-12-27 19:30:36 -08:00
p . Do ( actionAfterModule ) ;
__KernelRestoreActionType ( actionAfterModule , AfterModuleEntryCall : : Create ) ;
2012-12-27 14:21:39 -08:00
p . DoMarker ( " sceKernelModule " ) ;
}
2012-11-04 19:01:20 +01:00
Module * __KernelLoadELFFromPtr ( const u8 * ptr , u32 loadAddress , std : : string * error_string )
2012-11-01 16:19:01 +01:00
{
2012-11-04 19:01:20 +01:00
Module * module = new Module ;
kernelObjects . Create ( module ) ;
2013-01-04 00:36:08 -08:00
memset ( & module - > nm , 0 , sizeof ( module - > nm ) ) ;
2012-11-01 16:19:01 +01:00
2012-11-05 14:54:28 +01:00
u8 * newptr = 0 ;
2013-01-02 00:36:34 +01:00
if ( * ( u32 * ) ptr = = 0x4543537e ) { // "~SCE"
INFO_LOG ( HLE , " ~SCE module, skipping header " ) ;
ptr + = * ( u32 * ) ( ptr + 4 ) ;
}
2012-11-01 16:19:01 +01:00
2012-11-05 14:54:28 +01:00
if ( * ( u32 * ) ptr = = 0x5053507e ) { // "~PSP"
2012-11-05 16:54:35 +01:00
// Decrypt module! YAY!
INFO_LOG ( HLE , " Decrypting ~PSP file " ) ;
PSP_Header * head = ( PSP_Header * ) ptr ;
const u8 * in = ptr ;
u32 size = head - > elf_size ;
if ( head - > psp_size > size )
{
size = head - > psp_size ;
}
newptr = new u8 [ head - > elf_size + head - > psp_size ] ;
ptr = newptr ;
2013-01-02 00:36:34 +01:00
int ret = pspDecryptPRX ( in , ( u8 * ) ptr , head - > psp_size ) ;
2013-03-25 00:07:30 +01:00
if ( ret = = MISSING_KEY ) {
// This should happen for all "kernel" modules so disabling.
// Reporting::ReportMessage("Missing PRX decryption key!");
2013-01-02 00:36:34 +01:00
* error_string = " Missing key " ;
2012-11-06 15:46:21 +01:00
delete [ ] newptr ;
2013-01-02 00:36:34 +01:00
module - > isFake = true ;
2013-01-03 16:13:08 +01:00
strncpy ( module - > nm . name , head - > modname , 28 ) ;
module - > nm . entry_addr = - 1 ;
module - > nm . gp_value = - 1 ;
2013-01-02 00:36:34 +01:00
return module ;
}
else if ( ret < = 0 )
{
2013-03-25 00:18:10 +01:00
ERROR_LOG ( HLE , " Failed decrypting PRX! That's not normal! ret = %i \n " , ret ) ;
Reporting : : ReportMessage ( " Failed decrypting the PRX (ret = %i, size = %i, psp_size = %i)! " , ret , head - > elf_size , head - > psp_size ) ;
2012-11-06 15:46:21 +01:00
}
}
2013-01-02 00:36:34 +01:00
2012-11-01 16:19:01 +01:00
if ( * ( u32 * ) ptr ! = 0x464c457f )
{
2013-03-26 00:54:00 -07:00
ERROR_LOG_REPORT ( HLE , " Wrong magic number %08x " , * ( u32 * ) ptr ) ;
2012-11-05 14:54:28 +01:00
* error_string = " File corrupt " ;
2013-03-25 00:07:30 +01:00
if ( newptr ) {
2012-11-05 16:54:35 +01:00
delete [ ] newptr ;
}
2012-11-05 14:54:28 +01:00
kernelObjects . Destroy < Module > ( module - > GetUID ( ) ) ;
2012-11-01 16:19:01 +01:00
return 0 ;
}
// Open ELF reader
ElfReader reader ( ( void * ) ptr ) ;
if ( ! reader . LoadInto ( loadAddress ) )
{
ERROR_LOG ( HLE , " LoadInto failed " ) ;
2012-11-05 16:54:35 +01:00
if ( newptr )
{
delete [ ] newptr ;
}
2012-11-05 14:54:28 +01:00
kernelObjects . Destroy < Module > ( module - > GetUID ( ) ) ;
2012-11-01 16:19:01 +01:00
return 0 ;
}
2012-11-17 14:20:04 +01:00
module - > memoryBlockAddr = reader . GetVaddr ( ) ;
2013-04-10 21:03:43 -07:00
module - > memoryBlockSize = reader . GetTotalSize ( ) ;
2012-11-01 16:19:01 +01:00
struct libent
{
u32 exportName ; //default 0
u16 bcdVersion ;
u16 moduleAttributes ;
u8 exportEntrySize ;
u8 numVariables ;
u16 numFunctions ;
u32 __entrytableAddr ;
} ;
struct PspModuleInfo
{
// 0, 0, 1, 1 ?
u16 moduleAttrs ; //0x0000 User Mode, 0x1000 Kernel Mode
u16 moduleVersion ;
// 28 bytes of module name, packed with 0's.
char name [ 28 ] ;
u32 gp ; // ptr to MIPS GOT data (global offset table)
u32 libent ; // ptr to .lib.ent section
u32 libentend ; // ptr to end of .lib.ent section
u32 libstub ; // ptr to .lib.stub section
u32 libstubend ; // ptr to end of .lib.stub section
} ;
2012-11-04 19:01:20 +01:00
SectionID sceModuleInfoSection = reader . GetSectionByName ( " .rodata.sceModuleInfo " ) ;
PspModuleInfo * modinfo ;
if ( sceModuleInfoSection ! = - 1 )
modinfo = ( PspModuleInfo * ) Memory : : GetPointer ( reader . GetSectionAddr ( sceModuleInfoSection ) ) ;
else
2012-12-28 01:05:03 +01:00
modinfo = ( PspModuleInfo * ) Memory : : GetPointer ( reader . GetSegmentVaddr ( 0 ) + ( reader . GetSegmentPaddr ( 0 ) & 0x7FFFFFFF ) - reader . GetSegmentOffset ( 0 ) ) ;
2012-11-04 19:01:20 +01:00
2013-01-03 16:13:08 +01:00
module - > nm . gp_value = modinfo - > gp ;
strncpy ( module - > nm . name , modinfo - > name , 28 ) ;
2012-11-05 18:03:02 +01:00
// Check for module blacklist - we don't allow games to load these modules from disc
// as we have HLE implementations and the originals won't run in the emu because they
// directly access hardware or for other reasons.
for ( u32 i = 0 ; i < ARRAY_SIZE ( blacklistedModules ) ; i + + ) {
if ( strcmp ( modinfo - > name , blacklistedModules [ i ] ) = = 0 ) {
* error_string = " Blacklisted " ;
if ( newptr )
{
delete [ ] newptr ;
}
2013-01-02 00:48:30 +01:00
module - > isFake = true ;
2013-01-03 16:13:08 +01:00
module - > nm . entry_addr = - 1 ;
2013-01-02 00:48:30 +01:00
return module ;
2012-11-05 18:03:02 +01:00
}
}
2012-11-05 10:24:14 +01:00
bool hasSymbols = false ;
bool dontadd = false ;
SectionID textSection = reader . GetSectionByName ( " .text " ) ;
2012-11-05 16:54:35 +01:00
if ( textSection ! = - 1 )
2012-11-05 10:24:14 +01:00
{
2012-11-05 16:54:35 +01:00
u32 textStart = reader . GetSectionAddr ( textSection ) ;
u32 textSize = reader . GetSectionSize ( textSection ) ;
if ( ! host - > AttemptLoadSymbolMap ( ) )
2012-11-05 10:24:14 +01:00
{
2012-11-05 16:54:35 +01:00
hasSymbols = reader . LoadSymbols ( ) ;
if ( ! hasSymbols )
{
symbolMap . ResetSymbolMap ( ) ;
MIPSAnalyst : : ScanForFunctions ( textStart , textStart + textSize ) ;
}
}
else
{
dontadd = true ;
2012-11-05 10:24:14 +01:00
}
}
2013-03-30 21:42:43 -07:00
else if ( host - > AttemptLoadSymbolMap ( ) )
{
dontadd = true ;
}
2012-11-05 10:24:14 +01:00
2012-11-05 16:54:35 +01:00
INFO_LOG ( LOADER , " Module %s: %08x %08x %08x " , modinfo - > name , modinfo - > gp , modinfo - > libent , modinfo - > libstub ) ;
2012-11-01 16:19:01 +01:00
struct PspLibStubEntry
{
2012-11-04 19:01:20 +01:00
u32 name ;
u16 version ;
u16 flags ;
u16 size ;
u16 numFuncs ;
2012-11-01 16:19:01 +01:00
// each symbol has an associated nid; nidData is a pointer
// (in .rodata.sceNid section) to an array of longs, one
// for each function, which identifies the function whose
// address is to be inserted.
//
// The hash is the first 4 bytes of a SHA-1 hash of the function
// name. (Represented as a little-endian long, so the order
// of the bytes is reversed.)
u32 nidData ;
// the address of the function stubs where the function address jumps
// should be filled in
u32 firstSymAddr ;
} ;
int numModules = ( modinfo - > libstubend - modinfo - > libstub ) / sizeof ( PspLibStubEntry ) ;
DEBUG_LOG ( LOADER , " Num Modules: %i " , numModules ) ;
DEBUG_LOG ( LOADER , " =================================================== " ) ;
PspLibStubEntry * entry = ( PspLibStubEntry * ) Memory : : GetPointer ( modinfo - > libstub ) ;
int numSyms = 0 ;
2013-03-24 22:41:42 +01:00
for ( int m = 0 ; m < numModules ; m + + ) {
const char * modulename ;
if ( Memory : : IsValidAddress ( entry [ m ] . name ) )
modulename = ( const char * ) Memory : : GetPointer ( entry [ m ] . name ) ;
else
modulename = " (invalidname) " ;
if ( ! Memory : : IsValidAddress ( entry [ m ] . nidData ) ) {
ERROR_LOG ( LOADER , " Crazy niddata address %08x, skipping entire module " , entry [ m ] . nidData ) ;
continue ;
}
2012-11-01 16:19:01 +01:00
u32 * nidDataPtr = ( u32 * ) Memory : : GetPointer ( entry [ m ] . nidData ) ;
2012-11-05 10:05:09 +01:00
// u32 *stubs = (u32*)Memory::GetPointer(entry[m].firstSymAddr);
2012-11-01 16:19:01 +01:00
DEBUG_LOG ( LOADER , " Importing Module %s, stubs at %08x " , modulename , entry [ m ] . firstSymAddr ) ;
for ( int i = 0 ; i < entry [ m ] . numFuncs ; i + + )
{
u32 addrToWriteSyscall = entry [ m ] . firstSymAddr + i * 8 ;
DEBUG_LOG ( LOADER , " %s : %08x " , GetFuncName ( modulename , nidDataPtr [ i ] ) , addrToWriteSyscall ) ;
//write a syscall here
2013-03-24 22:41:42 +01:00
if ( Memory : : IsValidAddress ( addrToWriteSyscall ) )
WriteSyscall ( modulename , nidDataPtr [ i ] , addrToWriteSyscall ) ;
2012-11-01 16:19:01 +01:00
if ( ! dontadd )
{
char temp [ 256 ] ;
sprintf ( temp , " zz_%s " , GetFuncName ( modulename , nidDataPtr [ i ] ) ) ;
symbolMap . AddSymbol ( temp , addrToWriteSyscall , 8 , ST_FUNCTION ) ;
}
numSyms + + ;
}
DEBUG_LOG ( LOADER , " ------------------------------------------------------------- " ) ;
}
2012-11-05 10:24:14 +01:00
// Look at the exports, too.
2012-11-04 19:01:20 +01:00
struct PspLibEntEntry
{
u32 name ; /* ent's name (module name) address */
u16 version ;
u16 flags ;
u8 size ;
u8 vcount ;
u16 fcount ;
u32 resident ;
} ;
2012-11-01 16:19:01 +01:00
2012-11-04 19:01:20 +01:00
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 ;
2013-03-24 22:21:49 +01:00
if ( ent - > name = = 0 ) {
2012-11-04 19:01:20 +01:00
// ?
2012-11-17 14:20:04 +01:00
name = module - > nm . name ;
2012-11-04 19:01:20 +01:00
}
2013-03-24 22:21:49 +01:00
else if ( Memory : : IsValidAddress ( ent - > name ) ) {
2012-11-04 19:01:20 +01:00
name = ( const char * ) Memory : : GetPointer ( ent - > name ) ;
}
2013-03-24 22:21:49 +01:00
else {
name = " invalid? " ; // God Eater Burst
}
2012-11-04 19:01:20 +01:00
INFO_LOG ( HLE , " Exporting ent %d named %s, %d funcs, %d vars, resident %08x " , m , name , ent - > fcount , ent - > vcount , ent - > resident ) ;
2012-11-05 10:24:14 +01:00
2013-03-24 21:54:15 +01:00
// Seen 0x00060005 in God Eater Burst
if ( Memory : : IsValidAddress ( ent - > resident ) )
2012-11-04 19:01:20 +01:00
{
2013-03-24 21:54:15 +01:00
u32 * residentPtr = ( u32 * ) Memory : : GetPointer ( ent - > resident ) ;
2013-01-04 00:36:08 -08:00
2013-03-24 21:54:15 +01:00
for ( u32 j = 0 ; j < ent - > fcount ; j + + )
2013-01-04 00:36:08 -08:00
{
2013-03-24 21:54:15 +01:00
u32 nid = residentPtr [ j ] ;
u32 exportAddr = residentPtr [ ent - > fcount + ent - > vcount + j ] ;
switch ( nid )
{
case NID_MODULE_START :
module - > nm . module_start_func = exportAddr ;
break ;
case NID_MODULE_STOP :
module - > nm . module_stop_func = exportAddr ;
break ;
case NID_MODULE_REBOOT_BEFORE :
module - > nm . module_reboot_before_func = exportAddr ;
break ;
case NID_MODULE_REBOOT_PHASE :
module - > nm . module_reboot_phase_func = exportAddr ;
break ;
case NID_MODULE_BOOTSTART :
module - > nm . module_bootstart_func = exportAddr ;
break ;
default :
ResolveSyscall ( name , nid , exportAddr ) ;
}
2013-01-04 00:36:08 -08:00
}
2013-03-24 21:54:15 +01:00
for ( u32 j = 0 ; j < ent - > vcount ; j + + )
2013-01-04 00:36:08 -08:00
{
2013-03-24 21:54:15 +01:00
u32 nid = residentPtr [ ent - > fcount + j ] ;
u32 exportAddr = residentPtr [ ent - > fcount + ent - > vcount + ent - > fcount + j ] ;
switch ( nid )
{
case NID_MODULE_INFO :
break ;
case NID_MODULE_START_THREAD_PARAMETER :
if ( Memory : : Read_U32 ( exportAddr ) ! = 3 )
2013-03-26 00:54:00 -07:00
WARN_LOG_REPORT ( LOADER , " Strange value at module_start_thread_parameter export: %08x " , Memory : : Read_U32 ( exportAddr ) ) ;
2013-03-24 21:54:15 +01:00
module - > nm . module_start_thread_priority = Memory : : Read_U32 ( exportAddr + 4 ) ;
module - > nm . module_start_thread_stacksize = Memory : : Read_U32 ( exportAddr + 8 ) ;
module - > nm . module_start_thread_attr = Memory : : Read_U32 ( exportAddr + 12 ) ;
break ;
case NID_MODULE_STOP_THREAD_PARAMETER :
if ( Memory : : Read_U32 ( exportAddr ) ! = 3 )
2013-03-26 00:54:00 -07:00
WARN_LOG_REPORT ( LOADER , " Strange value at module_stop_thread_parameter export: %08x " , Memory : : Read_U32 ( exportAddr ) ) ;
2013-03-24 21:54:15 +01:00
module - > nm . module_stop_thread_priority = Memory : : Read_U32 ( exportAddr + 4 ) ;
module - > nm . module_stop_thread_stacksize = Memory : : Read_U32 ( exportAddr + 8 ) ;
module - > nm . module_stop_thread_attr = Memory : : Read_U32 ( exportAddr + 12 ) ;
break ;
case NID_MODULE_REBOOT_BEFORE_THREAD_PARAMETER :
if ( Memory : : Read_U32 ( exportAddr ) ! = 3 )
2013-03-26 00:54:00 -07:00
WARN_LOG_REPORT ( LOADER , " Strange value at module_reboot_before_thread_parameter export: %08x " , Memory : : Read_U32 ( exportAddr ) ) ;
2013-03-24 21:54:15 +01:00
module - > nm . module_reboot_before_thread_priority = Memory : : Read_U32 ( exportAddr + 4 ) ;
module - > nm . module_reboot_before_thread_stacksize = Memory : : Read_U32 ( exportAddr + 8 ) ;
module - > nm . module_reboot_before_thread_attr = Memory : : Read_U32 ( exportAddr + 12 ) ;
break ;
case NID_MODULE_SDK_VERSION :
DEBUG_LOG ( LOADER , " Module SDK: %08x " , Memory : : Read_U32 ( exportAddr ) ) ;
break ;
default :
DEBUG_LOG ( LOADER , " Unexpected variable with nid: %08x " , nid ) ;
break ;
}
2013-01-04 00:36:08 -08:00
}
2012-11-04 19:01:20 +01:00
}
2013-01-04 00:36:08 -08:00
2012-11-04 19:01:20 +01:00
if ( ent - > size > 4 )
{
ent = ( PspLibEntEntry * ) ( ( u8 * ) ent + ent - > size * 4 ) ;
}
else
{
ent + + ;
}
}
2012-11-17 14:20:04 +01:00
module - > nm . entry_addr = reader . GetEntryPoint ( ) ;
2013-03-03 17:11:05 +08:00
// use module_start_func instead of entry_addr if entry_addr is 0
if ( module - > nm . entry_addr = = 0 )
module - > nm . entry_addr = module - > nm . module_start_func ;
2012-11-04 19:01:20 +01:00
2012-11-05 16:54:35 +01:00
if ( newptr )
{
delete [ ] newptr ;
}
2012-11-04 19:01:20 +01:00
return module ;
2012-11-01 16:19:01 +01:00
}
bool __KernelLoadPBP ( const char * filename , std : : string * error_string )
{
2012-11-05 10:05:09 +01:00
static const char * FileNames [ ] =
{
" PARAM.SFO " , " ICON0.PNG " , " ICON1.PMF " , " UNKNOWN.PNG " ,
" PIC1.PNG " , " SND0.AT3 " , " UNKNOWN.PSP " , " UNKNOWN.PSAR "
} ;
2012-11-01 16:19:01 +01:00
2013-04-08 21:46:41 +02:00
PBPReader pbp ( filename ) ;
if ( ! pbp . IsValid ( ) ) {
2012-11-01 16:19:01 +01:00
ERROR_LOG ( LOADER , " %s is not a valid homebrew PSP1.0 PBP " , filename ) ;
* error_string = " Not a valid homebrew PBP " ;
return false ;
}
2013-04-08 21:46:41 +02:00
size_t elfSize ;
u8 * elfData = pbp . GetSubFile ( PBP_EXECUTABLE_PSP , & elfSize ) ;
Module * module = __KernelLoadELFFromPtr ( elfData , PSP_GetDefaultLoadAddress ( ) , error_string ) ;
if ( ! module ) {
delete [ ] elfData ;
return false ;
2012-11-01 16:19:01 +01:00
}
2013-04-08 21:46:41 +02:00
mipsr4k . pc = module - > nm . entry_addr ;
delete [ ] elfData ;
2012-11-01 16:19:01 +01:00
return true ;
}
2012-11-04 19:01:20 +01:00
Module * __KernelLoadModule ( u8 * fileptr , SceKernelLMOption * options , std : : string * error_string )
2012-11-01 16:19:01 +01:00
{
2012-11-05 12:02:09 +01:00
Module * module = 0 ;
2012-11-01 16:19:01 +01:00
// Check for PBP
if ( memcmp ( fileptr , " \0 PBP " , 4 ) = = 0 )
{
// PBP!
u32 version ;
memcpy ( & version , fileptr + 4 , 4 ) ;
u32 offset0 , offsets [ 16 ] ;
int numfiles ;
memcpy ( & offset0 , fileptr + 8 , 4 ) ;
numfiles = ( offset0 - 8 ) / 4 ;
offsets [ 0 ] = offset0 ;
for ( int i = 1 ; i < numfiles ; i + + )
memcpy ( & offsets [ i ] , fileptr + 12 + 4 * i , 4 ) ;
2012-11-05 12:02:09 +01:00
module = __KernelLoadELFFromPtr ( fileptr + offsets [ 5 ] , PSP_GetDefaultLoadAddress ( ) , error_string ) ;
2012-11-01 16:19:01 +01:00
}
else
{
2012-11-05 12:02:09 +01:00
module = __KernelLoadELFFromPtr ( fileptr , PSP_GetDefaultLoadAddress ( ) , error_string ) ;
2012-11-01 16:19:01 +01:00
}
2012-11-05 12:02:09 +01:00
return module ;
2012-11-01 16:19:01 +01:00
}
void __KernelStartModule ( Module * m , int args , const char * argp , SceKernelSMOption * options )
{
2013-03-02 14:58:58 -08:00
if ( m - > nm . module_start_func ! = 0 & & m - > nm . module_start_func ! = ( u32 ) - 1 )
2013-01-04 00:36:08 -08:00
{
if ( m - > nm . module_start_func ! = m - > nm . entry_addr )
2013-03-26 00:54:00 -07:00
WARN_LOG_REPORT ( LOADER , " Main module has start func (%08x) different from entry (%08x)? " , m - > nm . module_start_func , m - > nm . entry_addr ) ;
2013-01-04 00:36:08 -08:00
}
2012-11-01 16:19:01 +01:00
__KernelSetupRootThread ( m - > GetUID ( ) , args , argp , options - > priority , options - > stacksize , options - > attribute ) ;
//TODO: if current thread, put it in wait state, waiting for the new thread
}
2012-11-17 14:20:04 +01:00
u32 __KernelGetModuleGP ( SceUID uid )
2012-11-01 16:19:01 +01:00
{
u32 error ;
2012-11-17 14:20:04 +01:00
Module * module = kernelObjects . Get < Module > ( uid , error ) ;
if ( module )
2012-11-01 16:19:01 +01:00
{
2012-11-17 14:20:04 +01:00
return module - > nm . gp_value ;
2012-11-01 16:19:01 +01:00
}
else
{
return 0 ;
}
}
bool __KernelLoadExec ( const char * filename , SceKernelLoadExecParam * param , std : : string * error_string )
{
// Wipe kernel here, loadexec should reset the entire system
2012-11-06 22:03:25 +01:00
if ( __KernelIsRunning ( ) )
2013-05-14 20:37:20 +08:00
{
2012-11-06 22:03:25 +01:00
__KernelShutdown ( ) ;
2013-05-14 20:37:20 +08:00
//HLE needs to be reset here
HLEShutdown ( ) ;
HLEInit ( ) ;
}
2012-11-06 22:03:25 +01:00
2012-12-27 19:30:36 -08:00
__KernelModuleInit ( ) ;
2012-11-01 16:19:01 +01:00
__KernelInit ( ) ;
2012-11-05 12:02:09 +01:00
2012-11-01 16:19:01 +01:00
PSPFileInfo info = pspFileSystem . GetFileInfo ( filename ) ;
2013-04-27 23:16:51 +02:00
if ( ! info . exists ) {
ERROR_LOG ( LOADER , " Failed to load executable %s - file doesn't exist " , filename ) ;
* error_string = " Could not find executable " ;
return false ;
}
2012-11-05 12:02:09 +01:00
2012-11-01 16:19:01 +01:00
u32 handle = pspFileSystem . OpenFile ( filename , FILEACCESS_READ ) ;
2012-11-17 19:56:28 +01:00
u8 * temp = new u8 [ ( int ) info . size + 0x1000000 ] ;
2012-11-01 16:19:01 +01:00
2012-11-05 12:02:09 +01:00
pspFileSystem . ReadFile ( handle , temp , ( size_t ) info . size ) ;
2012-11-01 16:19:01 +01:00
2012-11-17 14:20:04 +01:00
Module * module = __KernelLoadModule ( temp , 0 , error_string ) ;
2012-11-01 16:19:01 +01:00
2013-05-09 13:14:19 +02:00
if ( ! module | | module - > isFake )
{
if ( module )
kernelObjects . Destroy < Module > ( module - > GetUID ( ) ) ;
2012-11-01 16:19:01 +01:00
ERROR_LOG ( LOADER , " Failed to load module %s " , filename ) ;
2013-05-09 13:14:19 +02:00
* error_string = " Failed to load executable: " + * error_string ;
2013-04-27 23:16:51 +02:00
delete [ ] temp ;
2012-11-01 16:19:01 +01:00
return false ;
}
2012-11-17 14:20:04 +01:00
mipsr4k . pc = module - > nm . entry_addr ;
2012-11-01 16:19:01 +01:00
INFO_LOG ( LOADER , " Module entry: %08x " , mipsr4k . pc ) ;
delete [ ] temp ;
pspFileSystem . CloseFile ( handle ) ;
SceKernelSMOption option ;
option . size = sizeof ( SceKernelSMOption ) ;
option . attribute = PSP_THREAD_ATTR_USER ;
option . mpidstack = 2 ;
option . priority = 0x20 ;
option . stacksize = 0x40000 ; // crazy? but seems to be the truth
2013-01-07 01:05:26 -08:00
// Replace start options with module-specified values if they exist.
if ( module - > nm . module_start_thread_attr ! = 0 )
option . attribute = module - > nm . module_start_thread_attr ;
if ( module - > nm . module_start_thread_priority ! = 0 )
option . priority = module - > nm . module_start_thread_priority ;
if ( module - > nm . module_start_thread_stacksize ! = 0 )
option . stacksize = module - > nm . module_start_thread_stacksize ;
2012-11-17 14:20:04 +01:00
__KernelStartModule ( module , ( u32 ) strlen ( filename ) + 1 , filename , & option ) ;
2012-11-01 16:19:01 +01:00
2013-04-10 21:16:31 -07:00
__KernelStartIdleThreads ( module - > GetUID ( ) ) ;
2012-11-01 16:19:01 +01:00
return true ;
}
//TODO: second param
2012-11-12 00:25:14 +00:00
int sceKernelLoadExec ( const char * filename , u32 paramPtr )
2012-11-01 16:19:01 +01:00
{
SceKernelLoadExecParam * param = 0 ;
2012-11-12 00:25:14 +00:00
if ( paramPtr )
2012-11-01 16:19:01 +01:00
{
2012-11-12 00:25:14 +00:00
param = ( SceKernelLoadExecParam * ) Memory : : GetPointer ( paramPtr ) ;
2012-11-01 16:19:01 +01:00
}
2012-11-05 12:02:09 +01:00
PSPFileInfo info = pspFileSystem . GetFileInfo ( filename ) ;
if ( ! info . exists ) {
ERROR_LOG ( LOADER , " sceKernelLoadExec(%s, ...): File does not exist " , filename ) ;
2012-11-12 00:25:14 +00:00
return SCE_KERNEL_ERROR_NOFILE ;
2012-11-05 12:02:09 +01:00
}
s64 size = ( s64 ) info . size ;
if ( ! size )
{
ERROR_LOG ( LOADER , " sceKernelLoadExec(%s, ...): File is size 0 " , filename ) ;
2012-11-12 00:25:14 +00:00
return SCE_KERNEL_ERROR_ILLEGAL_OBJECT ;
2012-11-05 12:02:09 +01:00
}
DEBUG_LOG ( HLE , " sceKernelLoadExec(name=%s,...) " , filename ) ;
2012-11-01 16:19:01 +01:00
std : : string error_string ;
2012-11-05 12:02:09 +01:00
if ( ! __KernelLoadExec ( filename , param , & error_string ) ) {
2012-11-01 16:19:01 +01:00
ERROR_LOG ( HLE , " sceKernelLoadExec failed: %s " , error_string . c_str ( ) ) ;
2012-11-12 00:25:14 +00:00
return - 1 ;
2012-11-05 12:02:09 +01:00
}
2012-11-12 00:25:14 +00:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
2013-03-07 19:43:17 +08:00
u32 sceKernelLoadModule ( const char * name , u32 flags , u32 optionAddr )
2012-11-01 16:19:01 +01:00
{
2013-03-07 23:18:33 -08:00
if ( ! name ) {
ERROR_LOG ( LOADER , " sceKernelLoadModule(NULL, %08x): Bad name " , flags ) ;
return SCE_KERNEL_ERROR_ILLEGAL_ADDR ;
}
2012-11-10 12:16:23 +01:00
2012-11-05 12:02:09 +01:00
PSPFileInfo info = pspFileSystem . GetFileInfo ( name ) ;
std : : string error_string ;
s64 size = ( s64 ) info . size ;
2012-11-04 19:01:20 +01:00
2012-11-05 12:02:09 +01:00
if ( ! info . exists ) {
ERROR_LOG ( LOADER , " sceKernelLoadModule(%s, %08x): File does not exist " , name , flags ) ;
return SCE_KERNEL_ERROR_NOFILE ;
}
2012-11-04 19:01:20 +01:00
2012-12-26 08:52:40 +01:00
if ( ! size ) {
2012-11-05 12:02:09 +01:00
ERROR_LOG ( LOADER , " sceKernelLoadModule(%s, %08x): Module file is size 0 " , name , flags ) ;
return SCE_KERNEL_ERROR_ILLEGAL_OBJECT ;
}
2012-11-04 19:01:20 +01:00
2012-11-07 15:44:48 +01:00
DEBUG_LOG ( LOADER , " sceKernelLoadModule(%s, %08x) " , name , flags ) ;
2012-11-05 12:02:09 +01:00
SceKernelLMOption * lmoption = 0 ;
int position = 0 ;
// TODO: Use position to decide whether to load high or low
2013-03-07 19:43:17 +08:00
if ( optionAddr ) {
lmoption = ( SceKernelLMOption * ) Memory : : GetPointer ( optionAddr ) ;
2012-11-05 12:02:09 +01:00
}
2012-11-01 16:19:01 +01:00
2012-11-05 12:02:09 +01:00
Module * module = 0 ;
2012-11-05 18:03:02 +01:00
u8 * temp = new u8 [ ( int ) size ] ;
u32 handle = pspFileSystem . OpenFile ( name , FILEACCESS_READ ) ;
pspFileSystem . ReadFile ( handle , temp , ( size_t ) size ) ;
module = __KernelLoadELFFromPtr ( temp , 0 , & error_string ) ;
delete [ ] temp ;
pspFileSystem . CloseFile ( handle ) ;
2012-11-05 12:02:09 +01:00
if ( ! module ) {
2012-11-05 18:03:02 +01:00
// Module was blacklisted or couldn't be decrypted, which means it's a kernel module we don't want to run.
// Let's just act as if it worked.
NOTICE_LOG ( LOADER , " Module %s is blacklisted or undecryptable - we lie about success " , name ) ;
return 1 ;
2012-11-05 12:02:09 +01:00
}
2012-11-01 16:19:01 +01:00
2012-11-05 12:02:09 +01:00
if ( lmoption ) {
INFO_LOG ( HLE , " %i=sceKernelLoadModule(name=%s,flag=%08x,%08x,%08x,%08x,position = %08x) " ,
module - > GetUID ( ) , name , flags ,
2012-11-01 16:19:01 +01:00
lmoption - > size , lmoption - > mpidtext , lmoption - > mpiddata , lmoption - > position ) ;
2012-12-26 08:52:40 +01:00
} else {
2012-11-05 12:02:09 +01:00
INFO_LOG ( HLE , " %i=sceKernelLoadModule(name=%s,flag=%08x,(...)) " , module - > GetUID ( ) , name , flags ) ;
2012-11-01 16:19:01 +01:00
}
2012-11-04 19:01:20 +01:00
2013-03-07 23:18:33 -08:00
// TODO: This is not the right timing and probably not the right wait type, just an approximation.
2013-03-09 11:37:57 -08:00
return hleDelayResult ( module - > GetUID ( ) , " module loaded " , 500 ) ;
2012-11-01 16:19:01 +01:00
}
2012-11-17 14:20:04 +01:00
void sceKernelStartModule ( u32 moduleId , u32 argsize , u32 argAddr , u32 returnValueAddr , u32 optionAddr )
2012-11-01 16:19:01 +01:00
{
2012-11-17 14:20:04 +01:00
// Dunno what these three defaults should be...
u32 priority = 0x20 ;
u32 stacksize = 0x40000 ;
u32 attr = 0 ;
int stackPartition = 0 ;
if ( optionAddr ) {
SceKernelSMOption smoption ;
Memory : : ReadStruct ( optionAddr , & smoption ) ; ;
priority = smoption . priority ;
attr = smoption . attribute ;
stacksize = smoption . stacksize ;
stackPartition = smoption . mpidstack ;
2012-11-05 10:05:09 +01:00
}
2012-11-17 14:20:04 +01:00
u32 error ;
Module * module = kernelObjects . Get < Module > ( moduleId , error ) ;
if ( ! module ) {
RETURN ( error ) ;
return ;
2013-01-02 00:36:34 +01:00
} else if ( module - > isFake ) {
2013-01-03 00:56:17 -08:00
INFO_LOG ( HLE , " sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): faked (undecryptable module) " ,
2013-01-02 00:36:34 +01:00
moduleId , argsize , argAddr , returnValueAddr , optionAddr ) ;
2012-11-17 14:20:04 +01:00
} else {
2013-05-19 17:54:14 -07:00
WARN_LOG ( HLE , " sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x) " ,
2013-01-02 00:36:34 +01:00
moduleId , argsize , argAddr , returnValueAddr , optionAddr ) ;
2012-11-17 14:20:04 +01:00
u32 entryAddr = module - > nm . entry_addr ;
2013-03-02 14:58:58 -08:00
if ( entryAddr = = ( u32 ) - 1 | | entryAddr = = module - > memoryBlockAddr - 1 ) {
2013-01-03 00:56:17 -08:00
// TODO: Do these always take effect, or do they not override optionAddr?
2013-03-02 14:58:58 -08:00
if ( module - > nm . module_start_func ! = 0 & & module - > nm . module_start_func ! = ( u32 ) - 1 ) {
2013-01-03 00:56:17 -08:00
entryAddr = module - > nm . module_start_func ;
priority = module - > nm . module_start_thread_priority ;
attr = module - > nm . module_start_thread_attr ;
stacksize = module - > nm . module_start_thread_stacksize ;
} else {
// TODO: Fix, check return value? Or do we call nothing?
RETURN ( moduleId ) ;
return ;
}
2012-11-17 14:20:04 +01:00
}
2013-01-01 17:04:06 -08:00
SceUID threadID = __KernelCreateThread ( module - > nm . name , moduleId , entryAddr , priority , stacksize , attr , 0 ) ;
sceKernelStartThread ( threadID , argsize , argAddr ) ;
2013-01-03 00:56:17 -08:00
// TODO: This will probably return the wrong value?
2013-01-01 17:04:06 -08:00
sceKernelWaitThreadEnd ( threadID , 0 ) ;
2012-11-17 14:20:04 +01:00
}
2013-01-03 00:56:17 -08:00
// TODO: Is this the correct return value?
RETURN ( moduleId ) ;
2012-11-01 16:19:01 +01:00
}
2013-03-07 19:29:49 +08:00
u32 sceKernelStopModule ( u32 moduleId , u32 argSize , u32 argAddr , u32 returnValueAddr , u32 optionAddr )
2012-11-01 16:19:01 +01:00
{
2013-03-07 19:29:49 +08:00
ERROR_LOG ( HLE , " UNIMPL sceKernelStopModule(%08x, %08x, %08x, %08x, %08x) " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
2012-11-17 14:20:04 +01:00
// We should call the "stop" entry point and return the value in returnValueAddr. See StartModule.
2013-05-19 17:54:14 -07:00
// Possibly also kill all its threads?
2013-03-07 19:29:49 +08:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
2013-01-05 19:43:51 +01:00
u32 sceKernelUnloadModule ( u32 moduleId )
2012-11-01 16:19:01 +01:00
{
2013-01-05 19:43:51 +01:00
INFO_LOG ( HLE , " sceKernelUnloadModule(%i) " , moduleId ) ;
2012-11-07 19:10:52 +01:00
u32 error ;
Module * module = kernelObjects . Get < Module > ( moduleId , error ) ;
if ( ! module )
2013-01-05 19:43:51 +01:00
return error ;
2012-11-01 16:19:01 +01:00
2012-11-07 19:10:52 +01:00
kernelObjects . Destroy < Module > ( moduleId ) ;
2013-01-05 19:43:51 +01:00
return 0 ;
2012-11-01 16:19:01 +01:00
}
2013-05-19 17:54:14 -07:00
u32 sceKernelStopUnloadSelfModuleWithStatus ( u32 exitCode , u32 argSize , u32 argp , u32 statusAddr , u32 optionAddr )
2013-02-04 02:53:38 +08:00
{
2013-05-19 17:54:14 -07:00
ERROR_LOG_REPORT ( HLE , " UNIMPL sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): game has likely crashed " , exitCode , argSize , argp , statusAddr , optionAddr ) ;
// Probably similar to sceKernelStopModule, but games generally call this when they die.
2013-02-04 02:53:38 +08:00
return 0 ;
}
2013-04-10 21:03:43 -07:00
struct GetModuleIdByAddressArg
2012-11-01 16:19:01 +01:00
{
2013-04-10 21:03:43 -07:00
u32 addr ;
SceUID result ;
} ;
2012-12-08 15:22:29 +00:00
2013-04-10 21:03:43 -07:00
bool __GetModuleIdByAddressIterator ( Module * module , GetModuleIdByAddressArg * state )
{
const u32 start = module - > memoryBlockAddr , size = module - > memoryBlockSize ;
if ( start < = state - > addr & & start + size > state - > addr )
2012-12-08 15:22:29 +00:00
{
2013-04-10 21:03:43 -07:00
state - > result = module - > GetUID ( ) ;
return false ;
2012-12-08 15:22:29 +00:00
}
2013-04-10 21:03:43 -07:00
return true ;
}
2012-12-08 15:22:29 +00:00
2013-04-10 21:03:43 -07:00
u32 sceKernelGetModuleIdByAddress ( u32 moduleAddr )
{
GetModuleIdByAddressArg state ;
state . addr = moduleAddr ;
state . result = SCE_KERNEL_ERROR_UNKNOWN_MODULE ;
kernelObjects . Iterate ( & __GetModuleIdByAddressIterator , & state ) ;
if ( state . result = = SCE_KERNEL_ERROR_UNKNOWN_MODULE )
ERROR_LOG ( HLE , " sceKernelGetModuleIdByAddress(%08x): module not found " , moduleAddr )
else
DEBUG_LOG ( HLE , " %x=sceKernelGetModuleIdByAddress(%08x) " , state . result , moduleAddr ) ;
return state . result ;
2012-11-01 16:19:01 +01:00
}
2012-11-05 10:05:09 +01:00
2013-01-05 19:43:51 +01:00
u32 sceKernelGetModuleId ( )
2012-11-01 16:19:01 +01:00
{
2013-01-05 19:43:51 +01:00
INFO_LOG ( HLE , " sceKernelGetModuleId() " ) ;
return __KernelGetCurThreadModuleId ( ) ;
2012-11-01 16:19:01 +01:00
}
2013-05-19 17:54:14 -07:00
u32 sceKernelFindModuleByName ( const char * name )
2012-11-01 16:19:01 +01:00
{
2013-05-19 17:54:14 -07:00
ERROR_LOG_REPORT ( HLE , " UNIMPL sceKernelFindModuleByName(%s) " , name ) ;
2013-01-01 22:22:08 -03:00
return 1 ;
2012-11-01 16:19:01 +01:00
}
2013-01-02 00:36:34 +01:00
u32 sceKernelLoadModuleByID ( u32 id , u32 flags , u32 lmoptionPtr )
{
u32 error ;
2013-01-02 12:35:37 +01:00
u32 handle = __IoGetFileHandleFromId ( id , error ) ;
2013-03-02 14:58:58 -08:00
if ( handle = = ( u32 ) - 1 ) {
2013-01-02 00:36:34 +01:00
ERROR_LOG ( HLE , " sceKernelLoadModuleByID(%08x, %08x, %08x): could not open file id " , id , flags , lmoptionPtr ) ;
return error ;
}
SceKernelLMOption * lmoption = 0 ;
if ( lmoptionPtr ) {
lmoption = ( SceKernelLMOption * ) Memory : : GetPointer ( lmoptionPtr ) ;
}
2013-01-19 13:48:20 -08:00
u32 pos = ( u32 ) pspFileSystem . SeekFile ( handle , 0 , FILEMOVE_CURRENT ) ;
size_t size = pspFileSystem . SeekFile ( handle , 0 , FILEMOVE_END ) ;
2013-01-02 00:36:34 +01:00
std : : string error_string ;
2013-01-02 12:35:37 +01:00
pspFileSystem . SeekFile ( handle , pos , FILEMOVE_BEGIN ) ;
2013-01-02 00:36:34 +01:00
Module * module = 0 ;
u8 * temp = new u8 [ size ] ;
2013-01-02 12:35:37 +01:00
pspFileSystem . ReadFile ( handle , temp , size ) ;
2013-01-02 00:36:34 +01:00
module = __KernelLoadELFFromPtr ( temp , 0 , & error_string ) ;
delete [ ] temp ;
if ( ! module ) {
// Module was blacklisted or couldn't be decrypted, which means it's a kernel module we don't want to run.
// Let's just act as if it worked.
NOTICE_LOG ( LOADER , " Module %d is blacklisted or undecryptable - we lie about success " , id ) ;
return 1 ;
}
if ( lmoption ) {
INFO_LOG ( HLE , " %i=sceKernelLoadModuleByID(%d,flag=%08x,%08x,%08x,%08x,position = %08x) " ,
module - > GetUID ( ) , id , flags ,
lmoption - > size , lmoption - > mpidtext , lmoption - > mpiddata , lmoption - > position ) ;
} else {
INFO_LOG ( HLE , " %i=sceKernelLoadModuleByID(%d,flag=%08x,(...)) " , module - > GetUID ( ) , id , flags ) ;
}
return module - > GetUID ( ) ;
2012-11-17 14:20:04 +01:00
}
2012-11-05 10:05:09 +01:00
2012-12-13 11:39:49 +00:00
u32 sceKernelLoadModuleDNAS ( const char * name , u32 flags )
2012-12-12 16:40:53 +00:00
{
2013-05-19 17:54:14 -07:00
ERROR_LOG_REPORT ( HLE , " UNIMPL 0=sceKernelLoadModuleDNAS() " ) ;
2012-12-12 16:40:53 +00:00
return 0 ;
}
2013-01-05 19:43:51 +01:00
u32 sceKernelQueryModuleInfo ( u32 uid , u32 infoAddr )
{
INFO_LOG ( HLE , " sceKernelQueryModuleInfo(%i, %08x) " , uid , infoAddr ) ;
u32 error ;
Module * module = kernelObjects . Get < Module > ( uid , error ) ;
if ( ! module )
return error ;
if ( ! Memory : : IsValidAddress ( infoAddr ) ) {
ERROR_LOG ( HLE , " sceKernelQueryModuleInfo(%i, %08x) - bad infoAddr " , uid , infoAddr ) ;
return - 1 ;
}
ModuleInfo info ;
memcpy ( info . segmentaddr , module - > nm . segmentaddr , sizeof ( info . segmentaddr ) ) ;
memcpy ( info . segmentsize , module - > nm . segmentsize , sizeof ( info . segmentsize ) ) ;
info . nsegment = module - > nm . nsegment ;
info . entry_addr = module - > nm . entry_addr ;
info . gp_value = module - > nm . gp_value ;
info . text_addr = module - > nm . text_addr ;
info . text_size = module - > nm . text_size ;
info . data_size = module - > nm . data_size ;
info . bss_size = module - > nm . bss_size ;
info . attribute = module - > nm . attribute ;
info . version [ 0 ] = module - > nm . version [ 0 ] ;
info . version [ 1 ] = module - > nm . version [ 1 ] ;
memcpy ( info . name , module - > nm . name , 28 ) ;
Memory : : WriteStruct ( infoAddr , & info ) ;
return 0 ;
}
2012-11-01 16:19:01 +01:00
const HLEFunction ModuleMgrForUser [ ] =
{
2013-03-07 19:43:17 +08:00
{ 0x977DE386 , & WrapU_CUU < sceKernelLoadModule > , " sceKernelLoadModule " } ,
2012-12-09 00:03:38 +00:00
{ 0xb7f46618 , & WrapU_UUU < sceKernelLoadModuleByID > , " sceKernelLoadModuleByID " } ,
2012-11-17 14:20:04 +01:00
{ 0x50F0C1EC , & WrapV_UUUUU < sceKernelStartModule > , " sceKernelStartModule " } ,
2012-11-05 10:05:09 +01:00
{ 0xD675EBB8 , & sceKernelExitGame , " sceKernelSelfStopUnloadModule " } , //HACK
2013-03-07 19:29:49 +08:00
{ 0xd1ff982a , & WrapU_UUUUU < sceKernelStopModule > , " sceKernelStopModule " } ,
2013-01-05 19:43:51 +01:00
{ 0x2e0911aa , WrapU_U < sceKernelUnloadModule > , " sceKernelUnloadModule " } ,
2012-11-01 16:19:01 +01:00
{ 0x710F61B5 , 0 , " sceKernelLoadModuleMs " } ,
{ 0xF9275D98 , 0 , " sceKernelLoadModuleBufferUsbWlan " } , ///???
{ 0xCC1D3699 , 0 , " sceKernelStopUnloadSelfModule " } ,
2013-01-05 19:43:51 +01:00
{ 0x748CBED9 , WrapU_UU < sceKernelQueryModuleInfo > , " sceKernelQueryModuleInfo " } ,
2012-12-08 15:22:29 +00:00
{ 0xd8b73127 , & WrapU_U < sceKernelGetModuleIdByAddress > , " sceKernelGetModuleIdByAddress " } ,
2013-01-05 19:43:51 +01:00
{ 0xf0a26395 , WrapU_V < sceKernelGetModuleId > , " sceKernelGetModuleId " } ,
2013-02-04 02:53:38 +08:00
{ 0x8f2df740 , WrapU_UUUUU < sceKernelStopUnloadSelfModuleWithStatus > , " sceKernelStopUnloadSelfModuleWithStatus " } ,
2012-12-13 11:39:49 +00:00
{ 0xfef27dc1 , & WrapU_CU < sceKernelLoadModuleDNAS > , " sceKernelLoadModuleDNAS " } ,
2013-05-19 18:28:05 -07:00
{ 0x644395e2 , 0 , " sceKernelGetModuleIdList " } ,
2012-11-01 16:19:01 +01:00
} ;
void Register_ModuleMgrForUser ( )
{
RegisterModule ( " ModuleMgrForUser " , ARRAY_SIZE ( ModuleMgrForUser ) , ModuleMgrForUser ) ;
}