2012-11-01 15:19:01 +00: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 22:01:49 +00:00
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 15:19:01 +00: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 14:41:37 +00:00
# include <algorithm>
2013-05-20 04:41:07 +00:00
# include <string>
2012-11-05 14:41:37 +00:00
2013-05-26 17:28:08 +00:00
# include "Core/HLE/HLE.h"
# include "Core/HLE/HLETables.h"
2013-03-24 23:07:30 +00:00
# include "Core/Reporting.h"
2012-11-05 11:02:09 +00:00
# include "Common/FileUtil.h"
2012-11-01 15:19:01 +00:00
# include "../Host.h"
2013-04-08 19:46:41 +00: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 15:19:01 +00:00
# include "../Debugger/SymbolMap.h"
# include "../FileSystems/FileSystem.h"
# include "../FileSystems/MetaFileSystem.h"
# include "../Util/BlockAllocator.h"
2013-04-08 19:46:41 +00: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 15:19:01 +00:00
# include "sceKernel.h"
# include "sceKernelModule.h"
# include "sceKernelThread.h"
# include "sceKernelMemory.h"
2013-01-01 23:36:34 +00:00
# include "sceIo.h"
2012-11-01 15:19:01 +00:00
enum {
PSP_THREAD_ATTR_USER = 0x80000000
} ;
2013-01-04 08:36:08 +00: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 11:02:09 +00:00
static const char * blacklistedModules [ ] = {
2012-11-05 17:03:02 +00:00
" sceATRAC3plus_Library " ,
" sceFont_Library " ,
2012-11-07 19:59:56 +00:00
" SceFont_Library " ,
2013-02-03 07:40:44 +00:00
" SceHttp_Library " ,
" sceMpeg_library " ,
2012-11-05 17:03:02 +00:00
" sceNetAdhocctl_Library " ,
" sceNetAdhocDownload_Library " ,
" sceNetAdhocMatching_Library " ,
2013-02-03 21:13:42 +00:00
" sceNetApDialogDummy_Library " ,
2012-11-05 17:03:02 +00:00
" sceNetAdhoc_Library " ,
" sceNetApctl_Library " ,
" sceNetInet_Library " ,
2013-02-03 07:40:44 +00:00
" sceNetResolver_Library " ,
2012-11-05 17:03:02 +00:00
" sceNet_Library " ,
2013-02-03 23:54:50 +00:00
" sceSsl_Module " ,
2012-11-05 11:02:09 +00:00
} ;
2013-05-24 06:40:03 +00:00
struct VarSymbol {
char moduleName [ 32 ] ;
u32 symAddr ;
u32 nid ;
u8 type ;
} ;
2012-11-17 13:20:04 +00: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 18:43:51 +00: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 ] ;
} ;
2013-05-26 17:54:11 +00:00
struct ModuleWaitingThread
{
SceUID threadID ;
u32 statusPtr ;
} ;
2013-01-05 18:43:51 +00:00
2012-11-17 13:20:04 +00:00
class Module : public KernelObject
2012-11-01 15:19:01 +00:00
{
2012-11-17 13:20:04 +00:00
public :
2013-05-26 18:30:22 +00:00
Module ( ) : memoryBlockAddr ( 0 ) , isFake ( false ) , isStarted ( false ) { }
2012-11-17 13:20:04 +00:00
~ Module ( ) {
if ( memoryBlockAddr ) {
userMemory . Free ( memoryBlockAddr ) ;
}
}
const char * GetName ( ) { return nm . name ; }
2012-11-01 15:19:01 +00:00
const char * GetTypeName ( ) { return " Module " ; }
void GetQuickInfo ( char * ptr , int size )
{
// ignore size
2013-01-03 15:13:08 +00:00
sprintf ( ptr , " %sname=%s gp=%08x entry=%08x " ,
isFake ? " faked " : " " ,
2012-11-17 13:20:04 +00:00
nm . name ,
nm . gp_value ,
nm . entry_addr ) ;
2012-11-01 15:19:01 +00:00
}
static u32 GetMissingErrorCode ( ) { return SCE_KERNEL_ERROR_UNKNOWN_MODULE ; }
2012-12-27 06:45:19 +00:00
int GetIDType ( ) const { return PPSSPP_KERNEL_TMID_Module ; }
virtual void DoState ( PointerWrap & p )
{
p . Do ( nm ) ;
p . Do ( memoryBlockAddr ) ;
2013-04-11 04:03:43 +00:00
p . Do ( memoryBlockSize ) ;
2013-05-26 18:30:22 +00:00
p . Do ( isFake ) ;
p . Do ( isStarted ) ;
2013-05-26 17:54:11 +00:00
ModuleWaitingThread mwt = { 0 } ;
p . Do ( waitingThreads , mwt ) ;
2012-12-27 06:45:19 +00:00
p . DoMarker ( " Module " ) ;
}
2012-11-01 15:19:01 +00:00
2012-11-17 13:20:04 +00:00
NativeModule nm ;
2013-05-26 17:54:11 +00:00
std : : vector < ModuleWaitingThread > waitingThreads ;
2012-11-17 13:20:04 +00:00
u32 memoryBlockAddr ;
2013-04-11 04:03:43 +00:00
u32 memoryBlockSize ;
2013-01-01 23:36:34 +00:00
bool isFake ;
2013-05-26 18:30:22 +00:00
// Probably one of the NativeModule fields, but not sure...
bool isStarted ;
2012-11-01 15:19:01 +00:00
} ;
2012-12-27 06:45:19 +00:00
KernelObject * __KernelModuleObject ( )
{
return new Module ;
}
2012-12-28 03:30:36 +00:00
class AfterModuleEntryCall : public Action {
public :
AfterModuleEntryCall ( ) { }
SceUID moduleID_ ;
u32 retValAddr ;
2013-01-06 18:54:33 +00:00
virtual void run ( MipsCall & call ) ;
2012-12-28 03:30:36 +00:00
virtual void DoState ( PointerWrap & p ) {
p . Do ( moduleID_ ) ;
p . Do ( retValAddr ) ;
2012-12-28 21:01:46 +00:00
p . DoMarker ( " AfterModuleEntryCall " ) ;
2012-12-28 03:30:36 +00:00
}
static Action * Create ( ) {
return new AfterModuleEntryCall ;
}
} ;
2013-01-06 18:54:33 +00:00
void AfterModuleEntryCall : : run ( MipsCall & call ) {
2012-12-28 03:30:36 +00:00
Memory : : Write_U32 ( retValAddr , currentMIPS - > r [ 2 ] ) ;
}
2012-11-01 15:19:01 +00: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-28 03:30:36 +00:00
static int actionAfterModule ;
2013-05-24 06:40:03 +00:00
static std : : vector < VarSymbol > unresolvedVars ;
static std : : vector < VarSymbol > exportedVars ;
2012-11-01 15:19:01 +00:00
// STATE END
//////////////////////////////////////////////////////////////////////////
2012-12-28 03:30:36 +00:00
void __KernelModuleInit ( )
{
actionAfterModule = __KernelRegisterActionType ( AfterModuleEntryCall : : Create ) ;
}
2012-12-27 22:21:39 +00:00
void __KernelModuleDoState ( PointerWrap & p )
{
2012-12-28 03:30:36 +00:00
p . Do ( actionAfterModule ) ;
__KernelRestoreActionType ( actionAfterModule , AfterModuleEntryCall : : Create ) ;
2013-05-24 06:40:03 +00:00
VarSymbol vs = { " " } ;
p . Do ( unresolvedVars , vs ) ;
p . Do ( exportedVars , vs ) ;
2012-12-27 22:21:39 +00:00
p . DoMarker ( " sceKernelModule " ) ;
}
2013-05-24 06:40:03 +00:00
void __KernelModuleShutdown ( )
{
unresolvedVars . clear ( ) ;
exportedVars . clear ( ) ;
2013-05-26 23:29:21 +00:00
MIPSAnalyst : : Shutdown ( ) ;
2013-05-24 06:40:03 +00:00
}
void WriteVarSymbol ( u32 exportAddress , u32 relocAddress , u8 type )
{
2013-05-24 08:45:08 +00:00
static u32 lastHI16RelocAddress = 0 ;
static u32 lastHI16ExportAddress = 0 ;
2013-06-01 16:12:31 +00:00
static bool lastHI16Processed = false ;
static u32 lastHILO16Address = 0 ;
2013-05-24 08:45:08 +00:00
u32 relocData = Memory : : Read_Instruction ( relocAddress ) ;
switch ( type )
{
case R_MIPS_NONE :
WARN_LOG_REPORT ( LOADER , " Var relocation type NONE - %08x => %08x " , exportAddress , relocAddress ) ;
break ;
case R_MIPS_32 :
relocData + = exportAddress ;
break ;
// Not really tested, but should work...
/*
case R_MIPS_26 :
if ( exportAddress % 4 | | ( exportAddress > > 28 ) ! = ( ( relocAddress + 4 ) > > 28 ) )
WARN_LOG_REPORT ( LOADER , " Bad var relocation addresses for type 26 - %08x => %08x " , exportAddress , relocAddress )
else
relocData = ( relocData & ~ 0x03ffffff ) | ( ( relocData + ( exportAddress > > 2 ) ) & 0x03ffffff ) ;
break ;
*/
case R_MIPS_HI16 :
2013-06-01 16:12:31 +00:00
if ( lastHI16Processed )
WARN_LOG_REPORT ( LOADER , " Unsafe unpaired HI16 variable relocation @ %08x / %08x " , lastHI16RelocAddress , relocAddress ) ;
2013-05-24 08:45:08 +00:00
// After this will be an R_MIPS_LO16. If that addition overflows, we need to account for it in HI16.
// The R_MIPS_LO16 and R_MIPS_HI16 will often be *different* relocAddress values.
lastHI16RelocAddress = relocAddress ;
lastHI16ExportAddress = exportAddress ;
2013-06-01 16:12:31 +00:00
lastHI16Processed = false ;
2013-05-24 08:45:08 +00:00
break ;
case R_MIPS_LO16 :
{
// The ABI requires that these come in pairs.
if ( lastHI16ExportAddress ! = exportAddress )
{
ERROR_LOG_REPORT ( LOADER , " HI16 and LO16 imports do not match for %08x => %08x/%08x (hi16 export: %08x) " , exportAddress , lastHI16RelocAddress , relocAddress , lastHI16ExportAddress ) ;
break ;
}
u32 relocDataHi = Memory : : Read_Instruction ( lastHI16RelocAddress ) ;
// Sign extend the existing low value (e.g. from addiu.)
u32 full = ( relocDataHi < < 16 ) + ( s16 ) ( u16 ) ( relocData & 0xFFFF ) + exportAddress ;
2013-06-01 16:12:31 +00:00
if ( ! lastHI16Processed )
{
2013-06-01 14:43:23 +00:00
// The low instruction will be a signed add, which means (full & 0x8000) will subtract.
// We add 1 in that case so that it ends up the right value.
u16 high = ( full > > 16 ) + ( ( full & 0x8000 ) ? 1 : 0 ) ;
Memory : : Write_U32 ( ( relocDataHi & ~ 0xFFFF ) | high , lastHI16RelocAddress ) ;
2013-06-01 16:12:31 +00:00
lastHI16Processed = true ;
2013-06-01 14:43:23 +00:00
}
2013-06-01 16:12:31 +00:00
else if ( lastHILO16Address ! = full )
WARN_LOG_REPORT ( LOADER , " Potentially unsafe unpaired LO16 variable relocation @ %08x / %08x " , lastHI16RelocAddress , relocAddress ) ;
2013-05-24 08:45:08 +00:00
// And then this is the low relocation, hurray.
relocData = ( relocData & ~ 0xFFFF ) | ( full & 0xFFFF ) ;
2013-06-01 16:12:31 +00:00
lastHILO16Address = full ;
2013-05-24 08:45:08 +00:00
}
break ;
default :
WARN_LOG_REPORT ( LOADER , " Unsupported var relocation type %d - %08x => %08x " , type , exportAddress , relocAddress ) ;
}
Memory : : Write_U32 ( relocData , relocAddress ) ;
2013-05-24 06:40:03 +00:00
}
void ImportVarSymbol ( const char * moduleName , u32 nid , u32 address , u8 type )
{
_dbg_assert_msg_ ( HLE , moduleName ! = NULL , " Invalid module name. " ) ;
if ( nid = = 0 )
{
// TODO: What's the right thing for this?
2013-05-24 08:45:08 +00:00
ERROR_LOG_REPORT ( LOADER , " Var import with nid = 0, type = %d " , type ) ;
return ;
}
if ( ! Memory : : IsValidAddress ( address ) )
{
ERROR_LOG_REPORT ( LOADER , " Invalid address for var import nid = %08x, type = %d, addr = %08x " , nid , type , address ) ;
2013-05-24 06:40:03 +00:00
return ;
}
for ( auto it = exportedVars . begin ( ) , end = exportedVars . end ( ) ; it ! = end ; + + it )
{
if ( ! strncmp ( it - > moduleName , moduleName , KERNELOBJECT_MAX_NAME_LENGTH ) & & it - > nid = = nid )
{
WriteVarSymbol ( it - > symAddr , address , type ) ;
return ;
}
}
// It hasn't been exported yet, but hopefully it will later.
INFO_LOG ( LOADER , " Variable (%s,%08x) unresolved, storing for later resolving " , moduleName , nid ) ;
VarSymbol vs = { " " , address , nid , type } ;
strncpy ( vs . moduleName , moduleName , KERNELOBJECT_MAX_NAME_LENGTH ) ;
vs . moduleName [ KERNELOBJECT_MAX_NAME_LENGTH ] = ' \0 ' ;
unresolvedVars . push_back ( vs ) ;
}
void ExportVarSymbol ( const char * moduleName , u32 nid , u32 address )
{
_dbg_assert_msg_ ( HLE , moduleName ! = NULL , " Invalid module name. " ) ;
VarSymbol ex = { " " , address , nid } ;
strncpy ( ex . moduleName , moduleName , KERNELOBJECT_MAX_NAME_LENGTH ) ;
ex . moduleName [ KERNELOBJECT_MAX_NAME_LENGTH ] = ' \0 ' ;
exportedVars . push_back ( ex ) ;
for ( auto it = unresolvedVars . begin ( ) , end = unresolvedVars . end ( ) ; it ! = end ; + + it )
{
if ( strncmp ( it - > moduleName , moduleName , KERNELOBJECT_MAX_NAME_LENGTH ) = = 0 & & it - > nid = = nid )
{
INFO_LOG ( HLE , " Resolving var %s/%08x " , moduleName , nid ) ;
WriteVarSymbol ( address , it - > symAddr , it - > type ) ;
}
}
}
2012-11-04 18:01:20 +00:00
Module * __KernelLoadELFFromPtr ( const u8 * ptr , u32 loadAddress , std : : string * error_string )
2012-11-01 15:19:01 +00:00
{
2012-11-04 18:01:20 +00:00
Module * module = new Module ;
kernelObjects . Create ( module ) ;
2013-01-04 08:36:08 +00:00
memset ( & module - > nm , 0 , sizeof ( module - > nm ) ) ;
2012-11-01 15:19:01 +00:00
2012-11-05 13:54:28 +00:00
u8 * newptr = 0 ;
2013-01-01 23:36:34 +00:00
if ( * ( u32 * ) ptr = = 0x4543537e ) { // "~SCE"
INFO_LOG ( HLE , " ~SCE module, skipping header " ) ;
ptr + = * ( u32 * ) ( ptr + 4 ) ;
}
2012-11-01 15:19:01 +00:00
2012-11-05 13:54:28 +00:00
if ( * ( u32 * ) ptr = = 0x5053507e ) { // "~PSP"
2012-11-05 15:54:35 +00: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-01 23:36:34 +00:00
int ret = pspDecryptPRX ( in , ( u8 * ) ptr , head - > psp_size ) ;
2013-03-24 23:07:30 +00:00
if ( ret = = MISSING_KEY ) {
// This should happen for all "kernel" modules so disabling.
// Reporting::ReportMessage("Missing PRX decryption key!");
2013-01-01 23:36:34 +00:00
* error_string = " Missing key " ;
2012-11-06 14:46:21 +00:00
delete [ ] newptr ;
2013-01-01 23:36:34 +00:00
module - > isFake = true ;
2013-01-03 15:13:08 +00:00
strncpy ( module - > nm . name , head - > modname , 28 ) ;
module - > nm . entry_addr = - 1 ;
module - > nm . gp_value = - 1 ;
2013-01-01 23:36:34 +00:00
return module ;
}
else if ( ret < = 0 )
{
2013-03-24 23:18:10 +00: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 14:46:21 +00:00
}
}
2013-01-01 23:36:34 +00:00
2012-11-01 15:19:01 +00:00
if ( * ( u32 * ) ptr ! = 0x464c457f )
{
2013-03-26 07:54:00 +00:00
ERROR_LOG_REPORT ( HLE , " Wrong magic number %08x " , * ( u32 * ) ptr ) ;
2012-11-05 13:54:28 +00:00
* error_string = " File corrupt " ;
2013-03-24 23:07:30 +00:00
if ( newptr ) {
2012-11-05 15:54:35 +00:00
delete [ ] newptr ;
}
2012-11-05 13:54:28 +00:00
kernelObjects . Destroy < Module > ( module - > GetUID ( ) ) ;
2012-11-01 15:19:01 +00:00
return 0 ;
}
// Open ELF reader
ElfReader reader ( ( void * ) ptr ) ;
if ( ! reader . LoadInto ( loadAddress ) )
{
ERROR_LOG ( HLE , " LoadInto failed " ) ;
2012-11-05 15:54:35 +00:00
if ( newptr )
{
delete [ ] newptr ;
}
2012-11-05 13:54:28 +00:00
kernelObjects . Destroy < Module > ( module - > GetUID ( ) ) ;
2012-11-01 15:19:01 +00:00
return 0 ;
}
2012-11-17 13:20:04 +00:00
module - > memoryBlockAddr = reader . GetVaddr ( ) ;
2013-04-11 04:03:43 +00:00
module - > memoryBlockSize = reader . GetTotalSize ( ) ;
2012-11-01 15:19:01 +00:00
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 18:01:20 +00:00
SectionID sceModuleInfoSection = reader . GetSectionByName ( " .rodata.sceModuleInfo " ) ;
PspModuleInfo * modinfo ;
if ( sceModuleInfoSection ! = - 1 )
modinfo = ( PspModuleInfo * ) Memory : : GetPointer ( reader . GetSectionAddr ( sceModuleInfoSection ) ) ;
else
2012-12-28 00:05:03 +00:00
modinfo = ( PspModuleInfo * ) Memory : : GetPointer ( reader . GetSegmentVaddr ( 0 ) + ( reader . GetSegmentPaddr ( 0 ) & 0x7FFFFFFF ) - reader . GetSegmentOffset ( 0 ) ) ;
2012-11-04 18:01:20 +00:00
2013-01-03 15:13:08 +00:00
module - > nm . gp_value = modinfo - > gp ;
strncpy ( module - > nm . name , modinfo - > name , 28 ) ;
2012-11-05 17:03:02 +00: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-01 23:48:30 +00:00
module - > isFake = true ;
2013-01-03 15:13:08 +00:00
module - > nm . entry_addr = - 1 ;
2013-01-01 23:48:30 +00:00
return module ;
2012-11-05 17:03:02 +00:00
}
}
2012-11-05 09:24:14 +00:00
bool hasSymbols = false ;
bool dontadd = false ;
SectionID textSection = reader . GetSectionByName ( " .text " ) ;
2012-11-05 15:54:35 +00:00
if ( textSection ! = - 1 )
2012-11-05 09:24:14 +00:00
{
2012-11-05 15:54:35 +00:00
u32 textStart = reader . GetSectionAddr ( textSection ) ;
u32 textSize = reader . GetSectionSize ( textSection ) ;
if ( ! host - > AttemptLoadSymbolMap ( ) )
2012-11-05 09:24:14 +00:00
{
2012-11-05 15:54:35 +00:00
hasSymbols = reader . LoadSymbols ( ) ;
if ( ! hasSymbols )
{
symbolMap . ResetSymbolMap ( ) ;
MIPSAnalyst : : ScanForFunctions ( textStart , textStart + textSize ) ;
}
}
else
{
dontadd = true ;
2012-11-05 09:24:14 +00:00
}
}
2013-03-31 04:42:43 +00:00
else if ( host - > AttemptLoadSymbolMap ( ) )
{
dontadd = true ;
}
2012-11-05 09:24:14 +00:00
2012-11-05 15:54:35 +00:00
INFO_LOG ( LOADER , " Module %s: %08x %08x %08x " , modinfo - > name , modinfo - > gp , modinfo - > libent , modinfo - > libstub ) ;
2012-11-01 15:19:01 +00:00
struct PspLibStubEntry
{
2012-11-04 18:01:20 +00:00
u32 name ;
u16 version ;
u16 flags ;
2013-05-22 06:31:50 +00:00
u8 size ;
u8 numVars ;
2012-11-04 18:01:20 +00:00
u16 numFuncs ;
2012-11-01 15:19:01 +00: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 ;
2013-05-22 06:31:50 +00:00
// Optional, this is where var relocations are.
// They use the format: u32 addr, u32 nid, ...
// WARNING: May have garbage if size < 6.
u32 varData ;
2013-05-23 05:12:11 +00:00
// Not sure what this is yet, assume garbage for now.
// TODO: Tales of the World: Radiant Mythology 2 has something here?
u32 extra ;
2012-11-01 15:19:01 +00:00
} ;
DEBUG_LOG ( LOADER , " =================================================== " ) ;
2013-05-20 15:54:03 +00:00
u32 * entryPos = ( u32 * ) Memory : : GetPointer ( modinfo - > libstub ) ;
u32 * entryEnd = ( u32 * ) Memory : : GetPointer ( modinfo - > libstubend ) ;
2012-11-01 15:19:01 +00:00
2013-05-20 04:41:07 +00:00
bool needReport = false ;
2013-05-20 15:54:03 +00:00
while ( entryPos < entryEnd ) {
2013-05-21 06:39:43 +00:00
PspLibStubEntry * entry = ( PspLibStubEntry * ) entryPos ;
2013-05-20 15:54:03 +00:00
entryPos + = entry - > size ;
2013-03-24 21:41:42 +00:00
const char * modulename ;
2013-05-20 15:54:03 +00:00
if ( Memory : : IsValidAddress ( entry - > name ) ) {
modulename = Memory : : GetCharPointer ( entry - > name ) ;
2013-05-20 04:41:07 +00:00
} else {
2013-03-24 21:41:42 +00:00
modulename = " (invalidname) " ;
2013-05-20 04:41:07 +00:00
needReport = true ;
}
2013-03-24 21:41:42 +00:00
2013-05-23 05:12:11 +00:00
DEBUG_LOG ( LOADER , " Importing Module %s, stubs at %08x " , modulename , entry - > firstSymAddr ) ;
if ( entry - > size ! = 5 & & entry - > size ! = 6 ) {
WARN_LOG_REPORT ( LOADER , " Unexpected module entry size %d " , entry - > size ) ;
2013-05-20 04:41:07 +00:00
needReport = true ;
2013-03-24 21:41:42 +00:00
}
2012-11-01 15:19:01 +00:00
2013-05-23 05:12:11 +00:00
// If nidData is 0, only variables are being imported.
if ( entry - > nidData ! = 0 ) {
if ( ! Memory : : IsValidAddress ( entry - > nidData ) ) {
ERROR_LOG_REPORT ( LOADER , " Crazy nidData address %08x, skipping entire module " , entry - > nidData ) ;
needReport = true ;
continue ;
}
u32 * nidDataPtr = ( u32 * ) Memory : : GetPointer ( entry - > nidData ) ;
for ( int i = 0 ; i < entry - > numFuncs ; + + i ) {
u32 addrToWriteSyscall = entry - > firstSymAddr + i * 8 ;
DEBUG_LOG ( LOADER , " %s : %08x " , GetFuncName ( modulename , nidDataPtr [ i ] ) , addrToWriteSyscall ) ;
//write a syscall here
if ( Memory : : IsValidAddress ( addrToWriteSyscall ) ) {
WriteSyscall ( modulename , nidDataPtr [ i ] , addrToWriteSyscall ) ;
} else {
WARN_LOG_REPORT ( LOADER , " Invalid address for syscall stub %s %08x " , modulename , nidDataPtr [ i ] ) ;
}
if ( ! dontadd ) {
char temp [ 256 ] ;
sprintf ( temp , " zz_%s " , GetFuncName ( modulename , nidDataPtr [ i ] ) ) ;
symbolMap . AddSymbol ( temp , addrToWriteSyscall , 8 , ST_FUNCTION ) ;
}
}
} else if ( entry - > numFuncs > 0 ) {
WARN_LOG_REPORT ( LOADER , " Module entry with %d imports but no valid address " , entry - > numFuncs ) ;
2013-05-22 06:31:50 +00:00
needReport = true ;
2013-05-20 15:54:03 +00:00
}
2012-11-01 15:19:01 +00:00
2013-05-23 05:12:11 +00:00
if ( entry - > varData ! = 0 ) {
if ( ! Memory : : IsValidAddress ( entry - > varData ) ) {
ERROR_LOG_REPORT ( LOADER , " Crazy varData address %08x, skipping rest of module " , entry - > varData ) ;
needReport = true ;
continue ;
2012-11-01 15:19:01 +00:00
}
2013-05-23 05:12:11 +00:00
2013-05-24 06:40:03 +00:00
for ( int i = 0 ; i < entry - > numVars ; + + i ) {
u32 varRefsPtr = Memory : : Read_U32 ( entry - > varData + i * 8 ) ;
u32 nid = Memory : : Read_U32 ( entry - > varData + i * 8 + 4 ) ;
if ( ! Memory : : IsValidAddress ( varRefsPtr ) ) {
WARN_LOG_REPORT ( LOADER , " Bad relocation list address for nid %08x in %s " , nid , modulename ) ;
continue ;
}
u32 * varRef = ( u32 * ) Memory : : GetPointer ( varRefsPtr ) ;
for ( ; * varRef ! = 0 ; + + varRef ) {
ImportVarSymbol ( modulename , nid , ( * varRef & 0x03FFFFFF ) < < 2 , * varRef > > 26 ) ;
}
2013-05-23 05:12:11 +00:00
}
} else if ( entry - > numVars > 0 ) {
WARN_LOG_REPORT ( LOADER , " Module entry with %d var imports but no valid address " , entry - > numVars ) ;
needReport = true ;
2012-11-01 15:19:01 +00:00
}
2013-05-23 05:12:11 +00:00
DEBUG_LOG ( LOADER , " ------------------------------------------------------------- " ) ;
2012-11-01 15:19:01 +00:00
}
2013-05-20 04:41:07 +00:00
if ( needReport ) {
std : : string debugInfo ;
2013-05-21 06:39:43 +00:00
entryPos = ( u32 * ) Memory : : GetPointer ( modinfo - > libstub ) ;
2013-05-20 15:54:03 +00:00
while ( entryPos < entryEnd ) {
2013-05-21 06:39:43 +00:00
PspLibStubEntry * entry = ( PspLibStubEntry * ) entryPos ;
2013-05-20 15:54:03 +00:00
entryPos + = entry - > size ;
2013-05-20 04:41:07 +00:00
char temp [ 512 ] ;
const char * modulename ;
2013-05-20 15:54:03 +00:00
if ( Memory : : IsValidAddress ( entry - > name ) ) {
modulename = Memory : : GetCharPointer ( entry - > name ) ;
2013-05-20 04:41:07 +00:00
} else {
modulename = " (invalidname) " ;
}
2013-05-23 05:12:11 +00:00
snprintf ( temp , sizeof ( temp ) , " %s ver=%04x, flags=%04x, size=%d, numVars=%d, numFuncs=%d, nidData=%08x, firstSym=%08x, varData=%08x, extra=%08x \n " ,
modulename , entry - > version , entry - > flags , entry - > size , entry - > numVars , entry - > numFuncs , entry - > nidData , entry - > firstSymAddr , entry - > size > = 6 ? entry - > varData : 0 , entry - > size > = 7 ? entry - > extra : 0 ) ;
2013-05-20 04:41:07 +00:00
debugInfo + = temp ;
}
Reporting : : ReportMessage ( " Module linking debug info: \n %s " , debugInfo . c_str ( ) ) ;
}
2012-11-05 09:24:14 +00:00
// Look at the exports, too.
2012-11-04 18:01:20 +00: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 15:19:01 +00:00
2013-05-21 06:39:43 +00:00
u32 * entPos = ( u32 * ) Memory : : GetPointer ( modinfo - > libent ) ;
u32 * entEnd = ( u32 * ) Memory : : GetPointer ( modinfo - > libentend ) ;
2013-05-23 05:12:11 +00:00
for ( int m = 0 ; entPos < entEnd ; + + m ) {
2013-05-21 06:39:43 +00:00
PspLibEntEntry * ent = ( PspLibEntEntry * ) entPos ;
2013-05-23 05:12:11 +00:00
entPos + = ent - > size ;
2013-05-21 06:39:43 +00:00
if ( ent - > size = = 0 ) {
2013-05-23 05:12:11 +00:00
WARN_LOG_REPORT ( LOADER , " Invalid export entry size %d " , ent - > size ) ;
2013-05-21 06:39:43 +00:00
entPos + = 4 ;
2012-11-04 18:01:20 +00:00
continue ;
2013-05-21 06:39:43 +00:00
}
2012-11-04 18:01:20 +00:00
2013-05-21 06:39:43 +00:00
const char * name ;
2013-05-23 05:12:11 +00:00
if ( Memory : : IsValidAddress ( ent - > name ) ) {
name = Memory : : GetCharPointer ( ent - > name ) ;
} else if ( ent - > name = = 0 ) {
2012-11-17 13:20:04 +00:00
name = module - > nm . name ;
2013-05-23 05:12:11 +00:00
} else {
2013-05-22 06:31:50 +00:00
name = " invalid? " ;
2013-03-24 21:21:49 +00:00
}
2012-11-04 18:01:20 +00:00
2013-05-23 05:12:11 +00:00
INFO_LOG ( HLE , " Exporting ent %d named %s, %d funcs, %d vars, resident %08x " , m , name , ent - > fcount , ent - > vcount , ent - > resident ) ;
2013-05-22 06:31:50 +00:00
2013-05-23 05:12:11 +00:00
if ( ! Memory : : IsValidAddress ( ent - > resident ) ) {
2013-05-25 22:14:34 +00:00
if ( ent - > fcount + ent - > vcount > 0 ) {
WARN_LOG_REPORT ( LOADER , " Invalid export resident address %08x " , ent - > resident ) ;
}
2013-05-23 05:12:11 +00:00
continue ;
}
2013-01-04 08:36:08 +00:00
2013-05-23 05:12:11 +00:00
u32 * residentPtr = ( u32 * ) Memory : : GetPointer ( ent - > resident ) ;
u32 * exportPtr = residentPtr + ent - > fcount + ent - > vcount ;
for ( u32 j = 0 ; j < ent - > fcount ; j + + ) {
u32 nid = residentPtr [ j ] ;
u32 exportAddr = exportPtr [ 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 08:36:08 +00:00
}
2013-05-23 05:12:11 +00:00
}
2013-01-04 08:36:08 +00:00
2013-05-23 05:12:11 +00:00
for ( u32 j = 0 ; j < ent - > vcount ; j + + ) {
u32 nid = residentPtr [ ent - > fcount + j ] ;
u32 exportAddr = exportPtr [ ent - > fcount + j ] ;
2013-05-25 22:14:34 +00:00
int size ;
2013-05-23 05:12:11 +00:00
switch ( nid ) {
case NID_MODULE_INFO :
break ;
case NID_MODULE_START_THREAD_PARAMETER :
2013-05-25 22:14:34 +00:00
size = Memory : : Read_U32 ( exportAddr ) ;
if ( size = = 0 )
break ;
else if ( size ! = 3 )
2013-05-23 05:12:11 +00:00
WARN_LOG_REPORT ( LOADER , " Strange value at module_start_thread_parameter export: %08x " , Memory : : Read_U32 ( exportAddr ) ) ;
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 :
2013-05-25 22:14:34 +00:00
size = Memory : : Read_U32 ( exportAddr ) ;
if ( size = = 0 )
break ;
else if ( size ! = 3 )
2013-05-23 05:12:11 +00:00
WARN_LOG_REPORT ( LOADER , " Strange value at module_stop_thread_parameter export: %08x " , Memory : : Read_U32 ( exportAddr ) ) ;
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 :
2013-05-25 22:14:34 +00:00
size = Memory : : Read_U32 ( exportAddr ) ;
if ( size = = 0 )
break ;
else if ( size ! = 3 )
2013-05-23 05:12:11 +00:00
WARN_LOG_REPORT ( LOADER , " Strange value at module_reboot_before_thread_parameter export: %08x " , Memory : : Read_U32 ( exportAddr ) ) ;
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 :
2013-05-24 06:40:03 +00:00
ExportVarSymbol ( name , nid , exportAddr ) ;
2013-05-23 05:12:11 +00:00
break ;
2013-01-04 08:36:08 +00:00
}
2012-11-04 18:01:20 +00:00
}
}
2012-11-17 13:20:04 +00:00
module - > nm . entry_addr = reader . GetEntryPoint ( ) ;
2013-03-03 09:11:05 +00: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 18:01:20 +00:00
2012-11-05 15:54:35 +00:00
if ( newptr )
{
delete [ ] newptr ;
}
2012-11-04 18:01:20 +00:00
return module ;
2012-11-01 15:19:01 +00:00
}
bool __KernelLoadPBP ( const char * filename , std : : string * error_string )
{
2012-11-05 09:05:09 +00:00
static const char * FileNames [ ] =
{
" PARAM.SFO " , " ICON0.PNG " , " ICON1.PMF " , " UNKNOWN.PNG " ,
" PIC1.PNG " , " SND0.AT3 " , " UNKNOWN.PSP " , " UNKNOWN.PSAR "
} ;
2012-11-01 15:19:01 +00:00
2013-04-08 19:46:41 +00:00
PBPReader pbp ( filename ) ;
if ( ! pbp . IsValid ( ) ) {
2012-11-01 15:19:01 +00: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 19:46:41 +00: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 15:19:01 +00:00
}
2013-04-08 19:46:41 +00:00
mipsr4k . pc = module - > nm . entry_addr ;
delete [ ] elfData ;
2012-11-01 15:19:01 +00:00
return true ;
}
2012-11-04 18:01:20 +00:00
Module * __KernelLoadModule ( u8 * fileptr , SceKernelLMOption * options , std : : string * error_string )
2012-11-01 15:19:01 +00:00
{
2012-11-05 11:02:09 +00:00
Module * module = 0 ;
2012-11-01 15:19:01 +00: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 11:02:09 +00:00
module = __KernelLoadELFFromPtr ( fileptr + offsets [ 5 ] , PSP_GetDefaultLoadAddress ( ) , error_string ) ;
2012-11-01 15:19:01 +00:00
}
else
{
2012-11-05 11:02:09 +00:00
module = __KernelLoadELFFromPtr ( fileptr , PSP_GetDefaultLoadAddress ( ) , error_string ) ;
2012-11-01 15:19:01 +00:00
}
2012-11-05 11:02:09 +00:00
return module ;
2012-11-01 15:19:01 +00:00
}
void __KernelStartModule ( Module * m , int args , const char * argp , SceKernelSMOption * options )
{
2013-05-26 18:30:22 +00:00
m - > isStarted = true ;
2013-03-02 22:58:58 +00:00
if ( m - > nm . module_start_func ! = 0 & & m - > nm . module_start_func ! = ( u32 ) - 1 )
2013-01-04 08:36:08 +00:00
{
if ( m - > nm . module_start_func ! = m - > nm . entry_addr )
2013-03-26 07:54:00 +00: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 08:36:08 +00:00
}
2013-05-26 17:28:08 +00:00
SceUID threadID = __KernelSetupRootThread ( m - > GetUID ( ) , args , argp , options - > priority , options - > stacksize , options - > attribute ) ;
__KernelSetThreadRA ( threadID , NID_MODULERETURN ) ;
2012-11-01 15:19:01 +00:00
}
2012-11-17 13:20:04 +00:00
u32 __KernelGetModuleGP ( SceUID uid )
2012-11-01 15:19:01 +00:00
{
u32 error ;
2012-11-17 13:20:04 +00:00
Module * module = kernelObjects . Get < Module > ( uid , error ) ;
if ( module )
2012-11-01 15:19:01 +00:00
{
2012-11-17 13:20:04 +00:00
return module - > nm . gp_value ;
2012-11-01 15:19:01 +00: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 21:03:25 +00:00
if ( __KernelIsRunning ( ) )
2013-05-14 12:37:20 +00:00
{
2012-11-06 21:03:25 +00:00
__KernelShutdown ( ) ;
2013-05-14 12:37:20 +00:00
//HLE needs to be reset here
HLEShutdown ( ) ;
HLEInit ( ) ;
}
2012-11-06 21:03:25 +00:00
2012-12-28 03:30:36 +00:00
__KernelModuleInit ( ) ;
2012-11-01 15:19:01 +00:00
__KernelInit ( ) ;
2012-11-05 11:02:09 +00:00
2012-11-01 15:19:01 +00:00
PSPFileInfo info = pspFileSystem . GetFileInfo ( filename ) ;
2013-04-27 21:16:51 +00: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 11:02:09 +00:00
2012-11-01 15:19:01 +00:00
u32 handle = pspFileSystem . OpenFile ( filename , FILEACCESS_READ ) ;
2012-11-17 18:56:28 +00:00
u8 * temp = new u8 [ ( int ) info . size + 0x1000000 ] ;
2012-11-01 15:19:01 +00:00
2012-11-05 11:02:09 +00:00
pspFileSystem . ReadFile ( handle , temp , ( size_t ) info . size ) ;
2012-11-01 15:19:01 +00:00
2012-11-17 13:20:04 +00:00
Module * module = __KernelLoadModule ( temp , 0 , error_string ) ;
2012-11-01 15:19:01 +00:00
2013-05-09 11:14:19 +00:00
if ( ! module | | module - > isFake )
{
if ( module )
kernelObjects . Destroy < Module > ( module - > GetUID ( ) ) ;
2012-11-01 15:19:01 +00:00
ERROR_LOG ( LOADER , " Failed to load module %s " , filename ) ;
2013-05-09 11:14:19 +00:00
* error_string = " Failed to load executable: " + * error_string ;
2013-04-27 21:16:51 +00:00
delete [ ] temp ;
2012-11-01 15:19:01 +00:00
return false ;
}
2012-11-17 13:20:04 +00:00
mipsr4k . pc = module - > nm . entry_addr ;
2012-11-01 15:19:01 +00: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 09:05:26 +00: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 13:20:04 +00:00
__KernelStartModule ( module , ( u32 ) strlen ( filename ) + 1 , filename , & option ) ;
2012-11-01 15:19:01 +00:00
2013-04-11 04:16:31 +00:00
__KernelStartIdleThreads ( module - > GetUID ( ) ) ;
2012-11-01 15:19:01 +00:00
return true ;
}
//TODO: second param
2012-11-12 00:25:14 +00:00
int sceKernelLoadExec ( const char * filename , u32 paramPtr )
2012-11-01 15:19:01 +00:00
{
SceKernelLoadExecParam * param = 0 ;
2012-11-12 00:25:14 +00:00
if ( paramPtr )
2012-11-01 15:19:01 +00:00
{
2012-11-12 00:25:14 +00:00
param = ( SceKernelLoadExecParam * ) Memory : : GetPointer ( paramPtr ) ;
2012-11-01 15:19:01 +00:00
}
2012-11-05 11:02:09 +00: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 11:02:09 +00: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 11:02:09 +00:00
}
DEBUG_LOG ( HLE , " sceKernelLoadExec(name=%s,...) " , filename ) ;
2012-11-01 15:19:01 +00:00
std : : string error_string ;
2012-11-05 11:02:09 +00:00
if ( ! __KernelLoadExec ( filename , param , & error_string ) ) {
2012-11-01 15:19:01 +00:00
ERROR_LOG ( HLE , " sceKernelLoadExec failed: %s " , error_string . c_str ( ) ) ;
2012-11-12 00:25:14 +00:00
return - 1 ;
2012-11-05 11:02:09 +00:00
}
2012-11-12 00:25:14 +00:00
return 0 ;
2012-11-01 15:19:01 +00:00
}
2013-03-07 11:43:17 +00:00
u32 sceKernelLoadModule ( const char * name , u32 flags , u32 optionAddr )
2012-11-01 15:19:01 +00:00
{
2013-03-08 07:18:33 +00:00
if ( ! name ) {
ERROR_LOG ( LOADER , " sceKernelLoadModule(NULL, %08x): Bad name " , flags ) ;
return SCE_KERNEL_ERROR_ILLEGAL_ADDR ;
}
2012-11-10 11:16:23 +00:00
2012-11-05 11:02:09 +00:00
PSPFileInfo info = pspFileSystem . GetFileInfo ( name ) ;
std : : string error_string ;
s64 size = ( s64 ) info . size ;
2012-11-04 18:01:20 +00:00
2012-11-05 11:02:09 +00:00
if ( ! info . exists ) {
ERROR_LOG ( LOADER , " sceKernelLoadModule(%s, %08x): File does not exist " , name , flags ) ;
return SCE_KERNEL_ERROR_NOFILE ;
}
2012-11-04 18:01:20 +00:00
2012-12-26 07:52:40 +00:00
if ( ! size ) {
2012-11-05 11:02:09 +00:00
ERROR_LOG ( LOADER , " sceKernelLoadModule(%s, %08x): Module file is size 0 " , name , flags ) ;
return SCE_KERNEL_ERROR_ILLEGAL_OBJECT ;
}
2012-11-04 18:01:20 +00:00
2012-11-07 14:44:48 +00:00
DEBUG_LOG ( LOADER , " sceKernelLoadModule(%s, %08x) " , name , flags ) ;
2012-11-05 11:02:09 +00:00
SceKernelLMOption * lmoption = 0 ;
int position = 0 ;
// TODO: Use position to decide whether to load high or low
2013-03-07 11:43:17 +00:00
if ( optionAddr ) {
lmoption = ( SceKernelLMOption * ) Memory : : GetPointer ( optionAddr ) ;
2012-11-05 11:02:09 +00:00
}
2012-11-01 15:19:01 +00:00
2012-11-05 11:02:09 +00:00
Module * module = 0 ;
2012-11-05 17:03:02 +00: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 11:02:09 +00:00
if ( ! module ) {
2012-11-05 17:03:02 +00: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 11:02:09 +00:00
}
2012-11-01 15:19:01 +00:00
2012-11-05 11:02:09 +00:00
if ( lmoption ) {
INFO_LOG ( HLE , " %i=sceKernelLoadModule(name=%s,flag=%08x,%08x,%08x,%08x,position = %08x) " ,
module - > GetUID ( ) , name , flags ,
2012-11-01 15:19:01 +00:00
lmoption - > size , lmoption - > mpidtext , lmoption - > mpiddata , lmoption - > position ) ;
2012-12-26 07:52:40 +00:00
} else {
2012-11-05 11:02:09 +00:00
INFO_LOG ( HLE , " %i=sceKernelLoadModule(name=%s,flag=%08x,(...)) " , module - > GetUID ( ) , name , flags ) ;
2012-11-01 15:19:01 +00:00
}
2012-11-04 18:01:20 +00:00
2013-03-08 07:18:33 +00:00
// TODO: This is not the right timing and probably not the right wait type, just an approximation.
2013-03-09 19:37:57 +00:00
return hleDelayResult ( module - > GetUID ( ) , " module loaded " , 500 ) ;
2012-11-01 15:19:01 +00:00
}
2013-05-29 02:39:28 +00:00
u32 sceKernelLoadModuleNpDrm ( const char * name , u32 flags , u32 optionAddr )
{
DEBUG_LOG ( LOADER , " sceKernelLoadModuleNpDrm(%s, %08x) " , name , flags ) ;
return sceKernelLoadModule ( name , flags , optionAddr ) ;
}
2012-11-17 13:20:04 +00:00
void sceKernelStartModule ( u32 moduleId , u32 argsize , u32 argAddr , u32 returnValueAddr , u32 optionAddr )
2012-11-01 15:19:01 +00:00
{
2012-11-17 13:20:04 +00:00
u32 priority = 0x20 ;
u32 stacksize = 0x40000 ;
u32 attr = 0 ;
int stackPartition = 0 ;
2013-05-23 07:31:30 +00:00
SceKernelSMOption smoption ;
2012-11-17 13:20:04 +00:00
if ( optionAddr ) {
2013-05-26 18:30:22 +00:00
Memory : : ReadStruct ( optionAddr , & smoption ) ;
2012-11-05 09:05:09 +00:00
}
2012-11-17 13:20:04 +00:00
u32 error ;
Module * module = kernelObjects . Get < Module > ( moduleId , error ) ;
if ( ! module ) {
RETURN ( error ) ;
return ;
2013-01-01 23:36:34 +00:00
} else if ( module - > isFake ) {
2013-01-03 08:56:17 +00:00
INFO_LOG ( HLE , " sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): faked (undecryptable module) " ,
2013-01-01 23:36:34 +00:00
moduleId , argsize , argAddr , returnValueAddr , optionAddr ) ;
2013-05-26 18:30:22 +00:00
if ( returnValueAddr )
Memory : : Write_U32 ( 0 , returnValueAddr ) ;
2013-05-23 07:31:30 +00:00
RETURN ( moduleId ) ;
return ;
2013-05-26 18:30:22 +00:00
} else if ( module - > isStarted ) {
ERROR_LOG ( HLE , " sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x) : already started " ,
moduleId , argsize , argAddr , returnValueAddr , optionAddr ) ;
// TODO: Maybe should be SCE_KERNEL_ERROR_ALREADY_STARTED, but I get SCE_KERNEL_ERROR_ERROR.
// But I also get crashes...
RETURN ( SCE_KERNEL_ERROR_ERROR ) ;
return ;
2012-11-17 13:20:04 +00:00
} else {
2013-05-23 07:31:30 +00:00
INFO_LOG ( HLE , " sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x) " ,
2013-01-01 23:36:34 +00:00
moduleId , argsize , argAddr , returnValueAddr , optionAddr ) ;
2013-05-23 07:31:30 +00:00
int attribute = module - > nm . attribute ;
2012-11-17 13:20:04 +00:00
u32 entryAddr = module - > nm . entry_addr ;
2013-05-23 07:31:30 +00:00
2013-05-30 23:36:06 +00:00
if ( module - > nm . module_start_func ! = 0 & & module - > nm . module_start_func ! = ( u32 ) - 1 )
2013-05-23 07:31:30 +00:00
{
2013-05-30 23:36:06 +00:00
entryAddr = module - > nm . module_start_func ;
2013-05-31 16:31:21 +00:00
attribute = module - > nm . module_start_thread_attr ;
}
2013-06-01 05:40:50 +00:00
else if ( ( entryAddr = = ( u32 ) - 1 ) | | entryAddr = = module - > memoryBlockAddr - 1 )
2013-05-31 16:31:21 +00:00
{
if ( optionAddr )
2013-05-24 14:06:31 +00:00
{
2013-05-31 16:31:21 +00:00
// TODO: Does sceKernelStartModule() really give an error when no entry only if you pass options?
2013-05-24 14:06:31 +00:00
attribute = smoption . attribute ;
}
else
{
2013-05-26 17:54:11 +00:00
// TODO: Why are we just returning the module ID in this case?
2013-05-31 16:31:21 +00:00
WARN_LOG ( HLE , " sceKernelStartModule(): module has no start or entry func " ) ;
2013-01-03 08:56:17 +00:00
RETURN ( moduleId ) ;
return ;
}
2012-11-17 13:20:04 +00:00
}
2013-01-02 01:04:06 +00:00
2013-05-23 07:31:30 +00:00
if ( Memory : : IsValidAddress ( entryAddr ) )
{
2013-05-23 16:25:13 +00:00
if ( ( optionAddr ) & & smoption . priority > 0 ) {
priority = smoption . priority ;
} else if ( module - > nm . module_start_thread_priority > 0 ) {
priority = module - > nm . module_start_thread_priority ;
}
2013-05-24 14:06:31 +00:00
2013-05-23 16:25:13 +00:00
if ( ( optionAddr ) & & ( smoption . stacksize > 0 ) ) {
stacksize = smoption . stacksize ;
} else if ( module - > nm . module_start_thread_stacksize > 0 ) {
stacksize = module - > nm . module_start_thread_stacksize ;
}
2013-05-23 07:31:30 +00:00
2013-05-23 16:25:13 +00:00
SceUID threadID = __KernelCreateThread ( module - > nm . name , moduleId , entryAddr , priority , stacksize , attribute , 0 ) ;
2013-05-23 07:31:30 +00:00
sceKernelStartThread ( threadID , argsize , argAddr ) ;
2013-05-26 17:54:11 +00:00
__KernelSetThreadRA ( threadID , NID_MODULERETURN ) ;
__KernelWaitCurThread ( WAITTYPE_MODULE , moduleId , 1 , 0 , false , " started module " ) ;
2013-05-23 07:31:30 +00:00
2013-05-26 17:54:11 +00:00
const ModuleWaitingThread mwt = { __KernelGetCurThread ( ) , returnValueAddr } ;
module - > waitingThreads . push_back ( mwt ) ;
2013-05-23 07:31:30 +00:00
}
else if ( entryAddr = = 0 )
{
2013-05-26 17:54:11 +00:00
INFO_LOG ( HLE , " sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): no entry address " ,
2013-05-23 07:31:30 +00:00
moduleId , argsize , argAddr , returnValueAddr , optionAddr ) ;
}
else
{
2013-05-26 17:54:11 +00:00
ERROR_LOG ( HLE , " sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): invalid entry address " ,
2013-05-23 07:31:30 +00:00
moduleId , argsize , argAddr , returnValueAddr , optionAddr ) ;
RETURN ( - 1 ) ;
2013-05-23 16:25:13 +00:00
return ;
2013-05-23 07:31:30 +00:00
}
2012-11-17 13:20:04 +00:00
}
2013-01-03 08:56:17 +00:00
RETURN ( moduleId ) ;
2012-11-01 15:19:01 +00:00
}
2013-03-07 11:29:49 +00:00
u32 sceKernelStopModule ( u32 moduleId , u32 argSize , u32 argAddr , u32 returnValueAddr , u32 optionAddr )
2012-11-01 15:19:01 +00:00
{
2013-05-26 18:30:22 +00:00
u32 priority = 0x20 ;
u32 stacksize = 0x40000 ;
u32 attr = 0 ;
// TODO: In a lot of cases (even for errors), this should resched. Needs testing.
u32 error ;
Module * module = kernelObjects . Get < Module > ( moduleId , error ) ;
if ( ! module )
{
ERROR_LOG ( HLE , " sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): invalid module id " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
return error ;
}
if ( module - > isFake )
{
INFO_LOG ( HLE , " sceKernelStopModule(%08x, %08x, %08x, %08x, %08x) - faking " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
if ( returnValueAddr )
Memory : : Write_U32 ( 0 , returnValueAddr ) ;
return 0 ;
}
if ( ! module - > isStarted )
{
ERROR_LOG ( HLE , " sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): already stopped " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
return SCE_KERNEL_ERROR_ALREADY_STOPPED ;
}
u32 stopFunc = module - > nm . module_stop_func ;
if ( module - > nm . module_stop_thread_priority ! = 0 )
priority = module - > nm . module_stop_thread_priority ;
if ( module - > nm . module_stop_thread_stacksize ! = 0 )
stacksize = module - > nm . module_stop_thread_stacksize ;
if ( module - > nm . module_stop_thread_attr ! = 0 )
attr = module - > nm . module_stop_thread_attr ;
// TODO: Need to test how this really works. Let's assume it's an override.
if ( Memory : : IsValidAddress ( optionAddr ) )
{
auto options = Memory : : GetStruct < SceKernelSMOption > ( optionAddr ) ;
// TODO: Check how size handling actually works.
if ( options - > size ! = 0 & & options - > priority ! = 0 )
priority = options - > priority ;
if ( options - > size ! = 0 & & options - > stacksize ! = 0 )
stacksize = options - > stacksize ;
if ( options - > size ! = 0 & & options - > attribute ! = 0 )
attr = options - > attribute ;
// TODO: Maybe based on size?
else if ( attr ! = 0 )
WARN_LOG_REPORT ( HLE , " Stopping module with attr=%x, but options specify 0 " , attr ) ;
}
if ( Memory : : IsValidAddress ( stopFunc ) )
{
SceUID threadID = __KernelCreateThread ( module - > nm . name , moduleId , stopFunc , priority , stacksize , attr , 0 ) ;
sceKernelStartThread ( threadID , argSize , argAddr ) ;
__KernelSetThreadRA ( threadID , NID_MODULERETURN ) ;
__KernelWaitCurThread ( WAITTYPE_MODULE , moduleId , 1 , 0 , false , " stopped module " ) ;
const ModuleWaitingThread mwt = { __KernelGetCurThread ( ) , returnValueAddr } ;
module - > waitingThreads . push_back ( mwt ) ;
}
else if ( stopFunc = = 0 )
{
INFO_LOG ( HLE , " sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): no stop func, skipping " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
module - > isStarted = false ;
}
else
{
ERROR_LOG_REPORT ( HLE , " sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): bad stop func address " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
module - > isStarted = false ;
}
2012-11-17 13:20:04 +00:00
2013-03-07 11:29:49 +00:00
return 0 ;
2012-11-01 15:19:01 +00:00
}
2013-01-05 18:43:51 +00:00
u32 sceKernelUnloadModule ( u32 moduleId )
2012-11-01 15:19:01 +00:00
{
2013-01-05 18:43:51 +00:00
INFO_LOG ( HLE , " sceKernelUnloadModule(%i) " , moduleId ) ;
2012-11-07 18:10:52 +00:00
u32 error ;
Module * module = kernelObjects . Get < Module > ( moduleId , error ) ;
if ( ! module )
2013-01-05 18:43:51 +00:00
return error ;
2012-11-01 15:19:01 +00:00
2012-11-07 18:10:52 +00:00
kernelObjects . Destroy < Module > ( moduleId ) ;
2013-05-26 04:07:41 +00:00
return moduleId ;
2012-11-01 15:19:01 +00:00
}
2013-05-20 00:54:14 +00:00
u32 sceKernelStopUnloadSelfModuleWithStatus ( u32 exitCode , u32 argSize , u32 argp , u32 statusAddr , u32 optionAddr )
2013-02-03 18:53:38 +00:00
{
2013-05-20 00:54:14 +00: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-03 18:53:38 +00:00
return 0 ;
}
2013-05-26 17:28:08 +00:00
void __KernelReturnFromModuleFunc ( )
{
// Return from the thread as normal.
__KernelReturnFromThread ( ) ;
2013-05-26 17:36:18 +00:00
SceUID leftModuleID = __KernelGetCurThreadModuleId ( ) ;
SceUID leftThreadID = __KernelGetCurThread ( ) ;
int exitStatus = sceKernelGetThreadExitStatus ( leftThreadID ) ;
// Reschedule immediately (to leave the thread) and delete it and its stack.
__KernelReSchedule ( " returned from module " ) ;
sceKernelDeleteThread ( leftThreadID ) ;
2013-05-26 17:54:11 +00:00
u32 error ;
Module * module = kernelObjects . Get < Module > ( leftModuleID , error ) ;
if ( ! module )
{
ERROR_LOG_REPORT ( HLE , " Returned from deleted module start/stop func " ) ;
return ;
}
// We can't be starting and stopping at the same time, so no need to differentiate.
2013-05-26 18:30:22 +00:00
module - > isStarted = ! module - > isStarted ;
2013-05-26 17:54:11 +00:00
for ( auto it = module - > waitingThreads . begin ( ) , end = module - > waitingThreads . end ( ) ; it < end ; + + it )
{
// Still waiting?
SceUID waitingModuleID = __KernelGetWaitID ( it - > threadID , WAITTYPE_MODULE , error ) ;
if ( waitingModuleID = = leftModuleID )
{
if ( it - > statusPtr ! = 0 )
Memory : : Write_U32 ( exitStatus , it - > statusPtr ) ;
__KernelResumeThreadFromWait ( it - > threadID , 0 ) ;
}
}
module - > waitingThreads . clear ( ) ;
2013-05-26 17:28:08 +00:00
}
2013-04-11 04:03:43 +00:00
struct GetModuleIdByAddressArg
2012-11-01 15:19:01 +00:00
{
2013-04-11 04:03:43 +00:00
u32 addr ;
SceUID result ;
} ;
2012-12-08 15:22:29 +00:00
2013-04-11 04:03:43 +00: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-11 04:03:43 +00:00
state - > result = module - > GetUID ( ) ;
return false ;
2012-12-08 15:22:29 +00:00
}
2013-04-11 04:03:43 +00:00
return true ;
}
2012-12-08 15:22:29 +00:00
2013-04-11 04:03:43 +00: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 15:19:01 +00:00
}
2012-11-05 09:05:09 +00:00
2013-01-05 18:43:51 +00:00
u32 sceKernelGetModuleId ( )
2012-11-01 15:19:01 +00:00
{
2013-01-05 18:43:51 +00:00
INFO_LOG ( HLE , " sceKernelGetModuleId() " ) ;
return __KernelGetCurThreadModuleId ( ) ;
2012-11-01 15:19:01 +00:00
}
2013-05-20 00:54:14 +00:00
u32 sceKernelFindModuleByName ( const char * name )
2012-11-01 15:19:01 +00:00
{
2013-05-20 00:54:14 +00:00
ERROR_LOG_REPORT ( HLE , " UNIMPL sceKernelFindModuleByName(%s) " , name ) ;
2013-01-02 01:22:08 +00:00
return 1 ;
2012-11-01 15:19:01 +00:00
}
2013-01-01 23:36:34 +00:00
u32 sceKernelLoadModuleByID ( u32 id , u32 flags , u32 lmoptionPtr )
{
u32 error ;
2013-01-02 11:35:37 +00:00
u32 handle = __IoGetFileHandleFromId ( id , error ) ;
2013-03-02 22:58:58 +00:00
if ( handle = = ( u32 ) - 1 ) {
2013-01-01 23:36:34 +00: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 21:48:20 +00:00
u32 pos = ( u32 ) pspFileSystem . SeekFile ( handle , 0 , FILEMOVE_CURRENT ) ;
size_t size = pspFileSystem . SeekFile ( handle , 0 , FILEMOVE_END ) ;
2013-01-01 23:36:34 +00:00
std : : string error_string ;
2013-01-02 11:35:37 +00:00
pspFileSystem . SeekFile ( handle , pos , FILEMOVE_BEGIN ) ;
2013-01-01 23:36:34 +00:00
Module * module = 0 ;
u8 * temp = new u8 [ size ] ;
2013-01-02 11:35:37 +00:00
pspFileSystem . ReadFile ( handle , temp , size ) ;
2013-01-01 23:36:34 +00: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 13:20:04 +00:00
}
2012-11-05 09:05:09 +00: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-20 00:54:14 +00:00
ERROR_LOG_REPORT ( HLE , " UNIMPL 0=sceKernelLoadModuleDNAS() " ) ;
2012-12-12 16:40:53 +00:00
return 0 ;
}
2013-01-05 18:43:51 +00: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 15:19:01 +00:00
const HLEFunction ModuleMgrForUser [ ] =
{
2013-03-07 11:43:17 +00:00
{ 0x977DE386 , & WrapU_CUU < sceKernelLoadModule > , " sceKernelLoadModule " } ,
2012-12-09 00:03:38 +00:00
{ 0xb7f46618 , & WrapU_UUU < sceKernelLoadModuleByID > , " sceKernelLoadModuleByID " } ,
2012-11-17 13:20:04 +00:00
{ 0x50F0C1EC , & WrapV_UUUUU < sceKernelStartModule > , " sceKernelStartModule " } ,
2012-11-05 09:05:09 +00:00
{ 0xD675EBB8 , & sceKernelExitGame , " sceKernelSelfStopUnloadModule " } , //HACK
2013-03-07 11:29:49 +00:00
{ 0xd1ff982a , & WrapU_UUUUU < sceKernelStopModule > , " sceKernelStopModule " } ,
2013-01-05 18:43:51 +00:00
{ 0x2e0911aa , WrapU_U < sceKernelUnloadModule > , " sceKernelUnloadModule " } ,
2012-11-01 15:19:01 +00:00
{ 0x710F61B5 , 0 , " sceKernelLoadModuleMs " } ,
{ 0xF9275D98 , 0 , " sceKernelLoadModuleBufferUsbWlan " } , ///???
{ 0xCC1D3699 , 0 , " sceKernelStopUnloadSelfModule " } ,
2013-01-05 18:43:51 +00:00
{ 0x748CBED9 , WrapU_UU < sceKernelQueryModuleInfo > , " sceKernelQueryModuleInfo " } ,
2012-12-08 15:22:29 +00:00
{ 0xd8b73127 , & WrapU_U < sceKernelGetModuleIdByAddress > , " sceKernelGetModuleIdByAddress " } ,
2013-01-05 18:43:51 +00:00
{ 0xf0a26395 , WrapU_V < sceKernelGetModuleId > , " sceKernelGetModuleId " } ,
2013-02-03 18:53:38 +00:00
{ 0x8f2df740 , WrapU_UUUUU < sceKernelStopUnloadSelfModuleWithStatus > , " sceKernelStopUnloadSelfModuleWithStatus " } ,
2012-12-13 11:39:49 +00:00
{ 0xfef27dc1 , & WrapU_CU < sceKernelLoadModuleDNAS > , " sceKernelLoadModuleDNAS " } ,
2013-05-20 01:28:05 +00:00
{ 0x644395e2 , 0 , " sceKernelGetModuleIdList " } ,
2013-05-29 02:39:28 +00:00
{ 0xf2d8d1b4 , & WrapU_CUU < sceKernelLoadModuleNpDrm > , " sceKernelLoadModuleNpDrm " } ,
2012-11-01 15:19:01 +00:00
} ;
void Register_ModuleMgrForUser ( )
{
RegisterModule ( " ModuleMgrForUser " , ARRAY_SIZE ( ModuleMgrForUser ) , ModuleMgrForUser ) ;
}