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-09-01 00:31:30 +00:00
# include <set>
2012-11-05 14:41:37 +00:00
2013-06-16 04:30:48 +00:00
# include "native/base/stringutil.h"
2013-12-29 22:28:31 +00:00
# include "Common/ChunkFile.h"
2013-09-01 07:32:17 +00:00
# include "Common/FileUtil.h"
2013-12-17 23:09:08 +00:00
# include "Core/Config.h"
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"
2013-09-01 07:32:17 +00:00
# include "Core/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"
2013-09-01 07:32:17 +00:00
# include "Core/FileSystems/FileSystem.h"
# include "Core/FileSystems/MetaFileSystem.h"
# include "Core/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"
2013-09-01 07:32:17 +00:00
# include "Core/MIPS/MIPS.h"
2012-11-01 15:19:01 +00:00
2013-09-01 07:32:17 +00:00
# include "Core/HLE/sceKernel.h"
# include "Core/HLE/sceKernelModule.h"
# include "Core/HLE/sceKernelThread.h"
# include "Core/HLE/sceKernelMemory.h"
# include "Core/HLE/sceIo.h"
2013-09-07 17:51:11 +00:00
# include "Core/HLE/KernelWaitHelpers.h"
2012-11-01 15:19:01 +00:00
2013-11-28 23:34:41 +00:00
# include "GPU/GPUState.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 ,
} ;
2013-06-11 09:48:45 +00:00
// This is a workaround for misbehaving homebrew (like TBL's Suicide Barbie (Final)).
static const char * lieAboutSuccessModules [ ] = {
" flash0:/kd/audiocodec.prx " ,
" flash0:/kd/libatrac3plus.prx " ,
2013-08-29 08:26:54 +00:00
" disc0:/PSP_GAME/SYSDIR/UPDATE/EBOOT.BIN " ,
2013-06-11 09:48:45 +00:00
} ;
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-08-31 23:26:31 +00:00
struct VarSymbolImport {
char moduleName [ KERNELOBJECT_MAX_NAME_LENGTH + 1 ] ;
2013-05-24 06:40:03 +00:00
u32 nid ;
2013-08-31 23:26:31 +00:00
u32 stubAddr ;
2013-05-24 06:40:03 +00:00
u8 type ;
} ;
2013-08-31 23:26:31 +00:00
struct VarSymbolExport {
bool Matches ( const VarSymbolImport & other ) const {
return ! strncmp ( moduleName , other . moduleName , KERNELOBJECT_MAX_NAME_LENGTH ) & & nid = = other . nid ;
}
char moduleName [ KERNELOBJECT_MAX_NAME_LENGTH + 1 ] ;
u32 nid ;
u32 symAddr ;
} ;
struct FuncSymbolImport {
char moduleName [ KERNELOBJECT_MAX_NAME_LENGTH + 1 ] ;
u32 stubAddr ;
u32 nid ;
} ;
struct FuncSymbolExport {
bool Matches ( const FuncSymbolImport & other ) const {
return ! strncmp ( moduleName , other . moduleName , KERNELOBJECT_MAX_NAME_LENGTH ) & & nid = = other . nid ;
}
char moduleName [ KERNELOBJECT_MAX_NAME_LENGTH + 1 ] ;
u32 symAddr ;
u32 nid ;
} ;
void ImportVarSymbol ( const VarSymbolImport & var ) ;
void ExportVarSymbol ( const VarSymbolExport & var ) ;
2013-09-01 00:31:30 +00:00
void UnexportVarSymbol ( const VarSymbolExport & var ) ;
2013-08-31 23:26:31 +00:00
2013-09-01 01:35:59 +00:00
void ImportFuncSymbol ( const FuncSymbolImport & func ) ;
void ExportFuncSymbol ( const FuncSymbolExport & func ) ;
void UnexportFuncSymbol ( const FuncSymbolExport & func ) ;
2012-11-17 13:20:04 +00:00
struct NativeModule {
2013-07-25 06:58:45 +00:00
u32_le next ;
u16_le attribute ;
2012-11-17 13:20:04 +00:00
u8 version [ 2 ] ;
char name [ 28 ] ;
2013-07-25 06:58:45 +00:00
u32_le status ;
u32_le unk1 ;
u32_le usermod_thid ;
u32_le memid ;
u32_le mpidtext ;
u32_le mpiddata ;
u32_le ent_top ;
u32_le ent_size ;
u32_le stub_top ;
u32_le stub_size ;
u32_le module_start_func ;
u32_le module_stop_func ;
u32_le module_bootstart_func ;
u32_le module_reboot_before_func ;
u32_le module_reboot_phase_func ;
u32_le entry_addr ;
u32_le gp_value ;
u32_le text_addr ;
u32_le text_size ;
u32_le data_size ;
u32_le bss_size ;
u32_le nsegment ;
u32_le segmentaddr [ 4 ] ;
u32_le segmentsize [ 4 ] ;
u32_le module_start_thread_priority ;
u32_le module_start_thread_stacksize ;
u32_le module_start_thread_attr ;
u32_le module_stop_thread_priority ;
u32_le module_stop_thread_stacksize ;
u32_le module_stop_thread_attr ;
u32_le module_reboot_before_thread_priority ;
u32_le module_reboot_before_thread_stacksize ;
u32_le module_reboot_before_thread_attr ;
2012-11-17 13:20:04 +00:00
} ;
2013-01-05 18:43:51 +00:00
// by QueryModuleInfo
struct ModuleInfo {
2013-12-09 08:45:54 +00:00
SceSize_le size ;
2013-07-25 06:58:45 +00:00
u32_le nsegment ;
u32_le segmentaddr [ 4 ] ;
u32_le segmentsize [ 4 ] ;
u32_le entry_addr ;
u32_le gp_value ;
u32_le text_addr ;
u32_le text_size ;
u32_le data_size ;
u32_le bss_size ;
u16_le attribute ;
2013-01-05 18:43:51 +00:00
u8 version [ 2 ] ;
char name [ 28 ] ;
} ;
2014-01-12 21:37:31 +00:00
struct ModuleWaitingThread {
2013-05-26 17:54:11 +00:00
SceUID threadID ;
u32 statusPtr ;
} ;
2013-01-05 18:43:51 +00:00
2014-01-12 21:37:31 +00:00
enum NativeModuleStatus {
MODULE_STATUS_STARTING = 4 ,
MODULE_STATUS_STARTED = 5 ,
MODULE_STATUS_STOPPING = 6 ,
MODULE_STATUS_STOPPED = 7 ,
MODULE_STATUS_UNLOADING = 8 ,
} ;
class Module : public KernelObject {
2012-11-17 13:20:04 +00:00
public :
2014-01-12 21:37:31 +00:00
Module ( ) : memoryBlockAddr ( 0 ) , isFake ( false ) { }
2012-11-17 13:20:04 +00:00
~ Module ( ) {
if ( memoryBlockAddr ) {
userMemory . Free ( memoryBlockAddr ) ;
2014-01-26 04:59:14 +00:00
symbolMap . UnloadModule ( memoryBlockAddr , memoryBlockSize ) ;
2012-11-17 13:20:04 +00:00
}
}
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 ; }
2013-06-19 06:54:29 +00:00
static int GetStaticIDType ( ) { return PPSSPP_KERNEL_TMID_Module ; }
2012-12-27 06:45:19 +00:00
int GetIDType ( ) const { return PPSSPP_KERNEL_TMID_Module ; }
virtual void DoState ( PointerWrap & p )
{
2014-01-22 09:06:59 +00:00
auto s = p . Section ( " Module " , 1 , 3 ) ;
2013-09-15 03:23:03 +00:00
if ( ! s )
return ;
2012-12-27 06:45:19 +00:00
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 ) ;
2014-01-12 21:37:31 +00:00
if ( s < 2 ) {
bool isStarted = false ;
p . Do ( isStarted ) ;
if ( isStarted )
nm . status = MODULE_STATUS_STARTED ;
else
nm . status = MODULE_STATUS_STOPPED ;
}
2014-01-22 09:06:59 +00:00
if ( s > = 3 ) {
p . Do ( textStart ) ;
p . Do ( textEnd ) ;
}
2013-05-26 17:54:11 +00:00
ModuleWaitingThread mwt = { 0 } ;
p . Do ( waitingThreads , mwt ) ;
2013-12-17 23:09:08 +00:00
FuncSymbolExport fsx = { { 0 } } ;
2013-08-31 23:26:31 +00:00
p . Do ( exportedFuncs , fsx ) ;
2013-12-17 23:09:08 +00:00
FuncSymbolImport fsi = { { 0 } } ;
2013-08-31 23:26:31 +00:00
p . Do ( importedFuncs , fsi ) ;
2013-12-17 23:09:08 +00:00
VarSymbolExport vsx = { { 0 } } ;
2013-08-31 23:26:31 +00:00
p . Do ( exportedVars , vsx ) ;
2013-12-17 23:09:08 +00:00
VarSymbolImport vsi = { { 0 } } ;
2013-08-31 23:26:31 +00:00
p . Do ( importedVars , vsi ) ;
2013-09-01 00:45:17 +00:00
RebuildImpExpModuleNames ( ) ;
2014-01-26 04:59:14 +00:00
if ( p . mode = = p . MODE_READ ) {
char moduleName [ 29 ] = { 0 } ;
strncpy ( moduleName , nm . name , ARRAY_SIZE ( nm . name ) ) ;
symbolMap . AddModule ( moduleName , memoryBlockAddr , memoryBlockSize ) ;
}
2012-12-27 06:45:19 +00:00
}
2012-11-01 15:19:01 +00:00
2013-09-01 01:43:53 +00:00
// We don't do this in the destructor to avoid annoying messages on game shutdown.
void Cleanup ( ) ;
2013-08-31 23:26:31 +00:00
void ImportFunc ( const FuncSymbolImport & func ) {
if ( ! Memory : : IsValidAddress ( func . stubAddr ) ) {
WARN_LOG_REPORT ( LOADER , " Invalid address for syscall stub %s %08x " , func . moduleName , func . nid ) ;
return ;
}
DEBUG_LOG ( LOADER , " Importing %s : %08x " , GetFuncName ( func . moduleName , func . nid ) , func . stubAddr ) ;
// Add the symbol to the symbol map for debugging.
char temp [ 256 ] ;
sprintf ( temp , " zz_%s " , GetFuncName ( func . moduleName , func . nid ) ) ;
2013-11-27 12:33:30 +00:00
symbolMap . AddFunction ( temp , func . stubAddr , 8 ) ;
2013-08-31 23:26:31 +00:00
// Keep track and actually hook it up if possible.
importedFuncs . push_back ( func ) ;
2013-09-01 00:45:17 +00:00
impExpModuleNames . insert ( func . moduleName ) ;
2013-09-01 01:35:59 +00:00
ImportFuncSymbol ( func ) ;
2013-08-31 23:26:31 +00:00
}
void ImportVar ( const VarSymbolImport & var ) {
// Keep track and actually hook it up if possible.
importedVars . push_back ( var ) ;
2013-09-01 00:45:17 +00:00
impExpModuleNames . insert ( var . moduleName ) ;
2013-08-31 23:26:31 +00:00
ImportVarSymbol ( var ) ;
}
void ExportFunc ( const FuncSymbolExport & func ) {
exportedFuncs . push_back ( func ) ;
2013-09-01 00:45:17 +00:00
impExpModuleNames . insert ( func . moduleName ) ;
2013-09-01 01:35:59 +00:00
ExportFuncSymbol ( func ) ;
2013-08-31 23:26:31 +00:00
}
void ExportVar ( const VarSymbolExport & var ) {
exportedVars . push_back ( var ) ;
2013-09-01 00:45:17 +00:00
impExpModuleNames . insert ( var . moduleName ) ;
2013-08-31 23:26:31 +00:00
ExportVarSymbol ( var ) ;
}
2013-09-01 00:45:17 +00:00
template < typename T >
void RebuildImpExpList ( const std : : vector < T > & list ) {
for ( size_t i = 0 ; i < list . size ( ) ; + + i ) {
impExpModuleNames . insert ( list [ i ] . moduleName ) ;
}
}
void RebuildImpExpModuleNames ( ) {
impExpModuleNames . clear ( ) ;
RebuildImpExpList ( exportedFuncs ) ;
RebuildImpExpList ( importedFuncs ) ;
RebuildImpExpList ( exportedVars ) ;
RebuildImpExpList ( importedVars ) ;
}
bool ImportsOrExportsModuleName ( const std : : string & moduleName ) {
return impExpModuleNames . find ( moduleName ) ! = impExpModuleNames . end ( ) ;
}
NativeModule nm ;
std : : vector < ModuleWaitingThread > waitingThreads ;
std : : vector < FuncSymbolExport > exportedFuncs ;
std : : vector < FuncSymbolImport > importedFuncs ;
std : : vector < VarSymbolExport > exportedVars ;
std : : vector < VarSymbolImport > importedVars ;
std : : set < std : : string > impExpModuleNames ;
2013-11-30 19:57:44 +00:00
// Keep track of the code region so we can throw out analysis results
// when unloaded.
u32 textStart ;
u32 textEnd ;
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 ;
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 ) {
2013-09-15 03:23:03 +00:00
auto s = p . Section ( " AfterModuleEntryCall " , 1 ) ;
if ( ! s )
return ;
2012-12-28 03:30:36 +00:00
p . Do ( moduleID_ ) ;
p . Do ( retValAddr ) ;
}
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
{
2013-07-25 06:58:45 +00:00
u32_le size ;
u32_le mpidtext ;
u32_le mpiddata ;
u32_le threadpriority ;
u32_le threadattributes ;
2012-11-01 15:19:01 +00:00
} ;
struct SceKernelLMOption {
2013-07-25 06:58:45 +00:00
SceSize_le size ;
SceUID_le mpidtext ;
SceUID_le mpiddata ;
u32_le flags ;
2012-11-01 15:19:01 +00:00
char position ;
char access ;
char creserved [ 2 ] ;
} ;
struct SceKernelSMOption {
2013-07-25 06:58:45 +00:00
SceSize_le size ;
SceUID_le mpidstack ;
SceSize_le stacksize ;
s32_le priority ;
u32_le attribute ;
2012-11-01 15:19:01 +00:00
} ;
//////////////////////////////////////////////////////////////////////////
// STATE BEGIN
2012-12-28 03:30:36 +00:00
static int actionAfterModule ;
2013-05-24 06:40:03 +00:00
2013-09-01 00:31:30 +00:00
static std : : set < SceUID > loadedModules ;
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 )
{
2014-01-22 09:06:59 +00:00
auto s = p . Section ( " sceKernelModule " , 1 , 2 ) ;
2013-09-15 03:23:03 +00:00
if ( ! s )
return ;
2012-12-28 03:30:36 +00:00
p . Do ( actionAfterModule ) ;
__KernelRestoreActionType ( actionAfterModule , AfterModuleEntryCall : : Create ) ;
2014-01-22 09:06:59 +00:00
if ( s > = 2 ) {
p . Do ( loadedModules ) ;
}
2012-12-27 22:21:39 +00:00
}
2013-05-24 06:40:03 +00:00
void __KernelModuleShutdown ( )
{
2013-09-01 00:31:30 +00:00
loadedModules . clear ( ) ;
2013-11-30 19:57:44 +00:00
MIPSAnalyst : : Reset ( ) ;
2013-05-24 06:40:03 +00:00
}
2013-06-24 05:25:26 +00:00
// Sometimes there are multiple LO16's or HI16's per pair, even though the ABI says nothing of this.
// For multiple LO16's, we need the original (unrelocated) instruction data of the HI16.
// For multiple HI16's, we just need to set each one.
struct HI16RelocInfo
{
u32 addr ;
u32 data ;
} ;
2013-09-01 00:31:30 +00:00
void WriteVarSymbol ( u32 exportAddress , u32 relocAddress , u8 type , bool reverse = false )
2013-05-24 06:40:03 +00:00
{
2013-06-22 18:59:35 +00:00
// We have to post-process the HI16 part, since it might be +1 or not depending on the LO16 value.
2013-05-24 08:45:08 +00:00
static u32 lastHI16ExportAddress = 0 ;
2013-06-22 19:44:25 +00:00
static std : : vector < HI16RelocInfo > lastHI16Relocs ;
2013-06-22 18:59:35 +00:00
static bool lastHI16Processed = true ;
2013-05-24 08:45:08 +00:00
2013-08-24 21:43:49 +00:00
u32 relocData = Memory : : Read_Instruction ( relocAddress ) . encoding ;
2013-05-24 08:45:08 +00:00
switch ( type )
{
case R_MIPS_NONE :
WARN_LOG_REPORT ( LOADER , " Var relocation type NONE - %08x => %08x " , exportAddress , relocAddress ) ;
break ;
case R_MIPS_32 :
2013-09-01 00:31:30 +00:00
if ( ! reverse ) {
relocData + = exportAddress ;
} else {
relocData - = exportAddress ;
}
2013-05-24 08:45:08 +00:00
break ;
// Not really tested, but should work...
/*
case R_MIPS_26 :
2013-09-01 00:31:30 +00:00
if ( exportAddress % 4 | | ( exportAddress > > 28 ) ! = ( ( relocAddress + 4 ) > > 28 ) ) {
2013-05-24 08:45:08 +00:00
WARN_LOG_REPORT ( LOADER , " Bad var relocation addresses for type 26 - %08x => %08x " , exportAddress , relocAddress )
2013-09-01 00:31:30 +00:00
} else {
if ( ! reverse ) {
relocData = ( relocData & ~ 0x03ffffff ) | ( ( relocData + ( exportAddress > > 2 ) ) & 0x03ffffff ) ;
} else {
relocData = ( relocData & ~ 0x03ffffff ) | ( ( relocData - ( exportAddress > > 2 ) ) & 0x03ffffff ) ;
}
}
2013-05-24 08:45:08 +00:00
break ;
*/
case R_MIPS_HI16 :
2013-09-01 00:31:30 +00:00
if ( lastHI16ExportAddress ! = exportAddress ) {
if ( ! lastHI16Processed & & lastHI16Relocs . size ( ) > = 1 ) {
2013-06-22 19:44:25 +00:00
WARN_LOG_REPORT ( LOADER , " Unsafe unpaired HI16 variable relocation @ %08x / %08x " , lastHI16Relocs [ lastHI16Relocs . size ( ) - 1 ] . addr , relocAddress ) ;
2013-09-01 00:31:30 +00:00
}
2013-06-22 19:44:25 +00:00
lastHI16ExportAddress = exportAddress ;
lastHI16Relocs . clear ( ) ;
}
2013-06-01 16:12:31 +00:00
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.
2013-06-22 19:44:25 +00:00
HI16RelocInfo reloc ;
reloc . addr = relocAddress ;
2013-08-24 21:43:49 +00:00
reloc . data = Memory : : Read_Instruction ( relocAddress ) . encoding ;
2013-06-22 19:44:25 +00:00
lastHI16Relocs . push_back ( reloc ) ;
2013-06-01 16:12:31 +00:00
lastHI16Processed = false ;
2013-05-24 08:45:08 +00:00
break ;
case R_MIPS_LO16 :
{
// Sign extend the existing low value (e.g. from addiu.)
2013-06-22 19:44:25 +00:00
const u32 exportOffsetLo = exportAddress + ( s16 ) ( u16 ) ( relocData & 0xFFFF ) ;
u32 full = exportOffsetLo ;
// The ABI requires that these come in pairs, at least.
2013-09-01 00:31:30 +00:00
if ( lastHI16Relocs . empty ( ) ) {
2013-06-22 19:44:25 +00:00
ERROR_LOG_REPORT ( LOADER , " LO16 without any HI16 variable import at %08x for %08x " , relocAddress , exportAddress )
// Try to process at least the low relocation...
2013-09-01 00:31:30 +00:00
} else if ( lastHI16ExportAddress ! = exportAddress ) {
2013-06-22 19:44:25 +00:00
ERROR_LOG_REPORT ( LOADER , " HI16 and LO16 imports do not match at %08x for %08x (should be %08x) " , relocAddress , lastHI16ExportAddress , exportAddress )
2013-09-01 00:31:30 +00:00
} else {
2013-06-22 19:44:25 +00:00
// Process each of the HI16. Usually there's only one.
for ( auto it = lastHI16Relocs . begin ( ) , end = lastHI16Relocs . end ( ) ; it ! = end ; + + it )
{
2013-09-01 00:31:30 +00:00
if ( ! reverse ) {
full = ( it - > data < < 16 ) + exportOffsetLo ;
} else {
full = ( it - > data < < 16 ) - exportOffsetLo ;
}
2013-06-22 19:44:25 +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 ( ( it - > data & ~ 0xFFFF ) | high , it - > addr ) ;
2013-12-14 23:05:56 +00:00
currentMIPS - > InvalidateICache ( it - > addr , 4 ) ;
2013-06-22 19:44:25 +00:00
}
2013-06-01 16:12:31 +00:00
lastHI16Processed = true ;
2013-06-01 14:43:23 +00:00
}
2013-05-24 08:45:08 +00:00
2013-06-22 19:44:25 +00:00
// With full set above (hopefully), now we just need to correct the low instruction.
2013-05-24 08:45:08 +00:00
relocData = ( relocData & ~ 0xFFFF ) | ( full & 0xFFFF ) ;
}
break ;
default :
WARN_LOG_REPORT ( LOADER , " Unsupported var relocation type %d - %08x => %08x " , type , exportAddress , relocAddress ) ;
}
Memory : : Write_U32 ( relocData , relocAddress ) ;
2013-09-01 07:32:17 +00:00
currentMIPS - > InvalidateICache ( relocAddress , 4 ) ;
2013-05-24 06:40:03 +00:00
}
2013-09-01 00:31:30 +00:00
void ImportVarSymbol ( const VarSymbolImport & var ) {
if ( var . nid = = 0 ) {
2013-05-24 06:40:03 +00:00
// TODO: What's the right thing for this?
2013-08-31 23:26:31 +00:00
ERROR_LOG_REPORT ( LOADER , " Var import with nid = 0, type = %d " , var . type ) ;
2013-05-24 08:45:08 +00:00
return ;
}
2013-09-01 00:31:30 +00:00
if ( ! Memory : : IsValidAddress ( var . stubAddr ) ) {
2013-08-31 23:26:31 +00:00
ERROR_LOG_REPORT ( LOADER , " Invalid address for var import nid = %08x, type = %d, addr = %08x " , var . nid , var . type , var . stubAddr ) ;
2013-05-24 06:40:03 +00:00
return ;
}
2013-09-01 00:31:30 +00:00
u32 error ;
for ( auto mod = loadedModules . begin ( ) , modend = loadedModules . end ( ) ; mod ! = modend ; + + mod ) {
Module * module = kernelObjects . Get < Module > ( * mod , error ) ;
2013-09-01 00:45:17 +00:00
if ( ! module | | ! module - > ImportsOrExportsModuleName ( var . moduleName ) ) {
2013-09-01 00:31:30 +00:00
continue ;
}
// Look for exports currently loaded modules already have. Maybe it's available?
for ( auto it = module - > exportedVars . begin ( ) , end = module - > exportedVars . end ( ) ; it ! = end ; + + it ) {
if ( it - > Matches ( var ) ) {
WriteVarSymbol ( it - > symAddr , var . stubAddr , var . type ) ;
return ;
}
2013-05-24 06:40:03 +00:00
}
}
// It hasn't been exported yet, but hopefully it will later.
2013-08-31 23:26:31 +00:00
INFO_LOG ( LOADER , " Variable (%s,%08x) unresolved, storing for later resolving " , var . moduleName , var . nid ) ;
2013-05-24 06:40:03 +00:00
}
2013-09-01 00:31:30 +00:00
void ExportVarSymbol ( const VarSymbolExport & var ) {
u32 error ;
for ( auto mod = loadedModules . begin ( ) , modend = loadedModules . end ( ) ; mod ! = modend ; + + mod ) {
Module * module = kernelObjects . Get < Module > ( * mod , error ) ;
2013-09-01 00:45:17 +00:00
if ( ! module | | ! module - > ImportsOrExportsModuleName ( var . moduleName ) ) {
2013-09-01 00:31:30 +00:00
continue ;
}
2013-05-24 06:40:03 +00:00
2013-09-01 00:31:30 +00:00
// Look for imports currently loaded modules already have, hook it up right away.
for ( auto it = module - > importedVars . begin ( ) , end = module - > importedVars . end ( ) ; it ! = end ; + + it ) {
if ( var . Matches ( * it ) ) {
2013-09-01 01:35:59 +00:00
INFO_LOG ( LOADER , " Resolving var %s/%08x " , var . moduleName , var . nid ) ;
2013-09-01 00:31:30 +00:00
WriteVarSymbol ( var . symAddr , it - > stubAddr , it - > type ) ;
}
}
}
}
2013-05-24 06:40:03 +00:00
2013-09-01 00:31:30 +00:00
void UnexportVarSymbol ( const VarSymbolExport & var ) {
u32 error ;
for ( auto mod = loadedModules . begin ( ) , modend = loadedModules . end ( ) ; mod ! = modend ; + + mod ) {
Module * module = kernelObjects . Get < Module > ( * mod , error ) ;
2013-09-01 00:45:17 +00:00
if ( ! module | | ! module - > ImportsOrExportsModuleName ( var . moduleName ) ) {
2013-09-01 00:31:30 +00:00
continue ;
}
2013-09-01 01:35:59 +00:00
// Look for imports modules that are *still* loaded have, and reverse them.
2013-09-01 00:31:30 +00:00
for ( auto it = module - > importedVars . begin ( ) , end = module - > importedVars . end ( ) ; it ! = end ; + + it ) {
if ( var . Matches ( * it ) ) {
2013-09-01 01:35:59 +00:00
INFO_LOG ( LOADER , " Unresolving var %s/%08x " , var . moduleName , var . nid ) ;
2013-09-01 00:31:30 +00:00
WriteVarSymbol ( var . symAddr , it - > stubAddr , it - > type , true ) ;
}
2013-05-24 06:40:03 +00:00
}
}
}
2013-09-01 01:35:59 +00:00
void ImportFuncSymbol ( const FuncSymbolImport & func ) {
// Prioritize HLE implementations.
// TODO: Or not?
if ( FuncImportIsSyscall ( func . moduleName , func . nid ) ) {
WriteSyscall ( func . moduleName , func . nid , func . stubAddr ) ;
2013-09-01 07:32:17 +00:00
currentMIPS - > InvalidateICache ( func . stubAddr , 8 ) ;
2013-09-01 01:35:59 +00:00
return ;
}
u32 error ;
for ( auto mod = loadedModules . begin ( ) , modend = loadedModules . end ( ) ; mod ! = modend ; + + mod ) {
Module * module = kernelObjects . Get < Module > ( * mod , error ) ;
if ( ! module | | ! module - > ImportsOrExportsModuleName ( func . moduleName ) ) {
continue ;
}
// Look for exports currently loaded modules already have. Maybe it's available?
for ( auto it = module - > exportedFuncs . begin ( ) , end = module - > exportedFuncs . end ( ) ; it ! = end ; + + it ) {
if ( it - > Matches ( func ) ) {
WriteFuncStub ( func . stubAddr , it - > symAddr ) ;
2013-09-01 07:32:17 +00:00
currentMIPS - > InvalidateICache ( func . stubAddr , 8 ) ;
2013-09-01 01:35:59 +00:00
return ;
}
}
}
// It hasn't been exported yet, but hopefully it will later.
if ( GetModuleIndex ( func . moduleName ) ! = - 1 ) {
2013-09-01 07:46:48 +00:00
WARN_LOG_REPORT ( LOADER , " Unknown syscall in known module: %s 0x%08x " , func . moduleName , func . nid ) ;
2013-09-01 01:35:59 +00:00
} else {
INFO_LOG ( LOADER , " Function (%s,%08x) unresolved, storing for later resolving " , func . moduleName , func . nid ) ;
}
WriteFuncMissingStub ( func . stubAddr , func . nid ) ;
2013-09-01 07:32:17 +00:00
currentMIPS - > InvalidateICache ( func . stubAddr , 8 ) ;
2013-09-01 01:35:59 +00:00
}
void ExportFuncSymbol ( const FuncSymbolExport & func ) {
if ( FuncImportIsSyscall ( func . moduleName , func . nid ) ) {
// Oops, HLE covers this.
WARN_LOG_REPORT ( LOADER , " Ignoring func export %s/%08x, already implemented in HLE. " , func . moduleName , func . nid ) ;
return ;
}
u32 error ;
for ( auto mod = loadedModules . begin ( ) , modend = loadedModules . end ( ) ; mod ! = modend ; + + mod ) {
Module * module = kernelObjects . Get < Module > ( * mod , error ) ;
if ( ! module | | ! module - > ImportsOrExportsModuleName ( func . moduleName ) ) {
continue ;
}
// Look for imports currently loaded modules already have, hook it up right away.
for ( auto it = module - > importedFuncs . begin ( ) , end = module - > importedFuncs . end ( ) ; it ! = end ; + + it ) {
if ( func . Matches ( * it ) ) {
INFO_LOG ( LOADER , " Resolving function %s/%08x " , func . moduleName , func . nid ) ;
WriteFuncStub ( it - > stubAddr , func . symAddr ) ;
2013-09-01 07:32:17 +00:00
currentMIPS - > InvalidateICache ( it - > stubAddr , 8 ) ;
2013-09-01 01:35:59 +00:00
}
}
}
}
void UnexportFuncSymbol ( const FuncSymbolExport & func ) {
if ( FuncImportIsSyscall ( func . moduleName , func . nid ) ) {
// Oops, HLE covers this.
return ;
}
u32 error ;
for ( auto mod = loadedModules . begin ( ) , modend = loadedModules . end ( ) ; mod ! = modend ; + + mod ) {
Module * module = kernelObjects . Get < Module > ( * mod , error ) ;
if ( ! module | | ! module - > ImportsOrExportsModuleName ( func . moduleName ) ) {
continue ;
}
// Look for imports modules that are *still* loaded have, and write back stubs.
for ( auto it = module - > importedFuncs . begin ( ) , end = module - > importedFuncs . end ( ) ; it ! = end ; + + it ) {
if ( func . Matches ( * it ) ) {
INFO_LOG ( LOADER , " Unresolving function %s/%08x " , func . moduleName , func . nid ) ;
WriteFuncMissingStub ( it - > stubAddr , it - > nid ) ;
2013-09-01 07:32:17 +00:00
currentMIPS - > InvalidateICache ( it - > stubAddr , 8 ) ;
2013-09-01 01:35:59 +00:00
}
}
}
}
2013-09-01 01:43:53 +00:00
void Module : : Cleanup ( ) {
2013-11-30 19:57:44 +00:00
MIPSAnalyst : : ForgetFunctions ( textStart , textEnd ) ;
2013-09-01 01:43:53 +00:00
loadedModules . erase ( GetUID ( ) ) ;
for ( auto it = exportedVars . begin ( ) , end = exportedVars . end ( ) ; it ! = end ; + + it ) {
UnexportVarSymbol ( * it ) ;
}
for ( auto it = exportedFuncs . begin ( ) , end = exportedFuncs . end ( ) ; it ! = end ; + + it ) {
UnexportFuncSymbol ( * it ) ;
}
}
2013-06-05 17:56:36 +00:00
Module * __KernelLoadELFFromPtr ( const u8 * ptr , u32 loadAddress , std : : string * error_string , u32 * magic ) {
2012-11-04 18:01:20 +00:00
Module * module = new Module ;
kernelObjects . Create ( module ) ;
2013-09-01 00:31:30 +00:00
loadedModules . insert ( module - > GetUID ( ) ) ;
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-07-25 06:58:45 +00:00
u32_le * magicPtr = ( u32_le * ) ptr ;
if ( * magicPtr = = 0x4543537e ) { // "~SCE"
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " ~SCE module, skipping header " ) ;
2013-07-28 16:07:00 +00:00
ptr + = * ( u32_le * ) ( ptr + 4 ) ;
2013-07-25 07:07:00 +00:00
magicPtr = ( u32_le * ) ptr ;
2013-01-01 23:36:34 +00:00
}
2013-07-25 06:58:45 +00:00
* magic = * magicPtr ;
2013-06-05 17:56:36 +00:00
if ( * magic = = 0x5053507e ) { // "~PSP"
2013-12-04 16:41:59 +00:00
DEBUG_LOG ( SCEMODULE , " Decrypting ~PSP file " ) ;
2012-11-05 15:54:35 +00:00
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-07-25 07:07:00 +00:00
magicPtr = ( u32_le * ) ptr ;
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 ;
2014-01-26 04:59:14 +00:00
strncpy ( module - > nm . name , head - > modname , ARRAY_SIZE ( module - > nm . name ) ) ;
2013-01-03 15:13:08 +00:00
module - > nm . entry_addr = - 1 ;
module - > nm . gp_value = - 1 ;
2013-01-01 23:36:34 +00:00
return module ;
2013-12-04 16:41:59 +00:00
} else if ( ret < = 0 ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEMODULE , " Failed decrypting PRX! That's not normal! ret = %i \n " , ret ) ;
2013-03-24 23:18:10 +00:00
Reporting : : ReportMessage ( " Failed decrypting the PRX (ret = %i, size = %i, psp_size = %i)! " , ret , head - > elf_size , head - > psp_size ) ;
2013-06-05 17:56:36 +00:00
// Fall through to safe exit in the next check.
2013-12-09 08:45:54 +00:00
} else {
// TODO: Is this right?
module - > nm . bss_size = head - > bss_size ;
2012-11-06 14:46:21 +00:00
}
}
2013-01-01 23:36:34 +00:00
2013-06-05 17:56:36 +00:00
// DO NOT change to else if, see above.
2013-07-25 06:58:45 +00:00
if ( * magicPtr ! = 0x464c457f ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG_REPORT ( SCEMODULE , " Wrong magic number %08x " , * magicPtr ) ;
2012-11-05 13:54:28 +00:00
* error_string = " File corrupt " ;
2013-06-05 17:56:36 +00:00
if ( newptr )
2012-11-05 15:54:35 +00:00
delete [ ] newptr ;
2013-09-01 01:43:53 +00:00
module - > Cleanup ( ) ;
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 ) ;
2013-10-05 08:05:55 +00:00
int result = reader . LoadInto ( loadAddress ) ;
if ( result ! = SCE_KERNEL_ERROR_OK ) {
ERROR_LOG ( SCEMODULE , " LoadInto failed with error %08x " , result ) ;
2012-11-05 15:54:35 +00:00
if ( newptr )
delete [ ] newptr ;
2013-09-01 01:43:53 +00:00
module - > Cleanup ( ) ;
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
2013-11-30 19:57:44 +00:00
struct PspModuleInfo {
2012-11-01 15:19:01 +00:00
// 0, 0, 1, 1 ?
2013-07-25 06:58:45 +00:00
u16_le moduleAttrs ; //0x0000 User Mode, 0x1000 Kernel Mode
u16_le moduleVersion ;
2012-11-01 15:19:01 +00:00
// 28 bytes of module name, packed with 0's.
char name [ 28 ] ;
2013-07-25 06:58:45 +00:00
u32_le gp ; // ptr to MIPS GOT data (global offset table)
u32_le libent ; // ptr to .lib.ent section
u32_le libentend ; // ptr to end of .lib.ent section
u32_le libstub ; // ptr to .lib.stub section
u32_le libstubend ; // ptr to end of .lib.stub section
2012-11-01 15:19:01 +00:00
} ;
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-12-09 08:45:54 +00:00
module - > nm . nsegment = reader . GetNumSegments ( ) ;
module - > nm . attribute = modinfo - > moduleAttrs ;
module - > nm . version [ 0 ] = modinfo - > moduleVersion & 0xFF ;
module - > nm . version [ 1 ] = modinfo - > moduleVersion > > 8 ;
module - > nm . data_size = 0 ;
// TODO: Is summing them up correct? Must not be since the numbers aren't exactly right.
for ( int i = 0 ; i < reader . GetNumSegments ( ) ; + + i ) {
module - > nm . data_size + = reader . GetSegmentDataSize ( i ) ;
}
2013-01-03 15:13:08 +00:00
module - > nm . gp_value = modinfo - > gp ;
2014-01-26 04:59:14 +00:00
strncpy ( module - > nm . name , modinfo - > name , ARRAY_SIZE ( module - > nm . name ) ) ;
// Let's also get a truncated version.
char moduleName [ 29 ] = { 0 } ;
strncpy ( moduleName , modinfo - > name , ARRAY_SIZE ( module - > nm . name ) ) ;
2013-01-03 15:13:08 +00:00
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 + + ) {
2014-01-26 04:59:14 +00:00
if ( strncmp ( modinfo - > name , blacklistedModules [ i ] , ARRAY_SIZE ( modinfo - > name ) ) = = 0 ) {
2012-11-05 17:03:02 +00:00
* 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
}
}
2014-01-26 04:59:14 +00:00
symbolMap . AddModule ( moduleName , module - > memoryBlockAddr , module - > memoryBlockSize ) ;
2012-11-05 09:24:14 +00:00
SectionID textSection = reader . GetSectionByName ( " .text " ) ;
2013-06-05 17:56:36 +00:00
if ( textSection ! = - 1 ) {
2012-11-05 15:54:35 +00:00
u32 textStart = reader . GetSectionAddr ( textSection ) ;
u32 textSize = reader . GetSectionSize ( textSection ) ;
2013-12-09 08:45:54 +00:00
module - > nm . text_addr = textStart ;
// TODO: This value appears to be wrong. In one example, the PSP has a value > 0x1000 bigger.
module - > nm . text_size = textSize ;
// TODO: It seems like the data size excludes the text size, which kinda makes sense?
module - > nm . data_size - = textSize ;
2014-02-08 18:29:22 +00:00
# if !defined(MOBILE_DEVICE)
2013-12-17 22:40:27 +00:00
bool gotSymbols = reader . LoadSymbols ( ) ;
MIPSAnalyst : : ScanForFunctions ( textStart , textStart + textSize , ! gotSymbols ) ;
2013-11-30 19:57:44 +00:00
# else
2013-12-17 23:09:08 +00:00
if ( g_Config . bFuncHashMap ) {
bool gotSymbols = reader . LoadSymbols ( ) ;
MIPSAnalyst : : ScanForFunctions ( textStart , textStart + textSize , ! gotSymbols ) ;
}
2013-10-22 12:41:19 +00:00
# endif
2013-03-31 04:42:43 +00:00
}
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
2013-11-30 19:57:44 +00:00
struct PspLibStubEntry {
2013-07-25 06:58:45 +00:00
u32_le name ;
u16_le version ;
u16_le flags ;
2013-05-22 06:31:50 +00:00
u8 size ;
u8 numVars ;
2013-07-25 06:58:45 +00:00
u16_le 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.)
2013-07-25 06:58:45 +00:00
u32_le nidData ;
2012-11-01 15:19:01 +00:00
// the address of the function stubs where the function address jumps
// should be filled in
2013-07-25 06:58:45 +00:00
u32_le 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.
2013-07-25 06:58:45 +00:00
u32_le 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?
2013-07-25 06:58:45 +00:00
u32_le extra ;
2012-11-01 15:19:01 +00:00
} ;
DEBUG_LOG ( LOADER , " =================================================== " ) ;
2013-07-25 06:58:45 +00:00
u32_le * entryPos = ( u32_le * ) Memory : : GetPointer ( modinfo - > libstub ) ;
u32_le * entryEnd = ( u32_le * ) Memory : : GetPointer ( modinfo - > libstubend ) ;
2012-11-01 15:19:01 +00:00
2013-12-02 03:43:40 +00:00
u32_le firstImportStubAddr = 0 ;
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 ) {
2013-07-31 07:00:45 +00:00
if ( entry - > size ! = 7 ) {
WARN_LOG_REPORT ( LOADER , " Unexpected module entry size %d " , entry - > size ) ;
needReport = true ;
} else if ( entry - > extra ! = 0 ) {
WARN_LOG_REPORT ( LOADER , " Unexpected module entry with non-zero 7th value %08x " , entry - > extra ) ;
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 ;
}
2013-08-31 23:26:31 +00:00
FuncSymbolImport func ;
strncpy ( func . moduleName , modulename , KERNELOBJECT_MAX_NAME_LENGTH ) ;
func . moduleName [ KERNELOBJECT_MAX_NAME_LENGTH ] = ' \0 ' ;
2013-07-25 06:58:45 +00:00
u32_le * nidDataPtr = ( u32_le * ) Memory : : GetPointer ( entry - > nidData ) ;
2013-05-23 05:12:11 +00:00
for ( int i = 0 ; i < entry - > numFuncs ; + + i ) {
2013-08-31 23:26:31 +00:00
// This is the id of the import.
func . nid = nidDataPtr [ i ] ;
// This is the address to write the j abnd delay slot to.
func . stubAddr = entry - > firstSymAddr + i * 8 ;
module - > ImportFunc ( func ) ;
2013-05-23 05:12:11 +00:00
}
2013-12-02 03:43:40 +00:00
2013-12-04 16:41:59 +00:00
if ( ! firstImportStubAddr | | firstImportStubAddr > entry - > firstSymAddr )
2013-12-02 03:43:40 +00:00
firstImportStubAddr = entry - > firstSymAddr ;
2013-05-23 05:12:11 +00:00
} 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-08-31 23:26:31 +00:00
VarSymbolImport var ;
strncpy ( var . moduleName , modulename , KERNELOBJECT_MAX_NAME_LENGTH ) ;
var . moduleName [ KERNELOBJECT_MAX_NAME_LENGTH ] = ' \0 ' ;
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 ;
}
2013-07-25 06:58:45 +00:00
u32_le * varRef = ( u32_le * ) Memory : : GetPointer ( varRefsPtr ) ;
2013-05-24 06:40:03 +00:00
for ( ; * varRef ! = 0 ; + + varRef ) {
2013-08-31 23:26:31 +00:00
var . nid = nid ;
var . stubAddr = ( * varRef & 0x03FFFFFF ) < < 2 ;
var . type = * varRef > > 26 ;
module - > ImportVar ( var ) ;
2013-05-24 06:40:03 +00:00
}
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-07-25 06:58:45 +00:00
entryPos = ( u32_le * ) 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 ( ) ) ;
}
2013-12-02 03:43:40 +00:00
if ( textSection = = - 1 ) {
u32 textStart = reader . GetVaddr ( ) ;
u32 textEnd = firstImportStubAddr - 4 ;
2014-02-08 18:29:22 +00:00
# if !defined(MOBILE_DEVICE)
2013-12-17 22:40:27 +00:00
bool gotSymbols = reader . LoadSymbols ( ) ;
MIPSAnalyst : : ScanForFunctions ( textStart , textEnd , ! gotSymbols ) ;
2013-12-17 23:09:08 +00:00
# else
if ( g_Config . bFuncHashMap ) {
bool gotSymbols = reader . LoadSymbols ( ) ;
MIPSAnalyst : : ScanForFunctions ( textStart , textEnd , ! gotSymbols ) ;
}
2013-12-02 03:43:40 +00:00
# endif
}
2012-11-05 09:24:14 +00:00
// Look at the exports, too.
2012-11-04 18:01:20 +00:00
struct PspLibEntEntry
{
2013-07-25 06:58:45 +00:00
u32_le name ; /* ent's name (module name) address */
u16_le version ;
u16_le flags ;
2012-11-04 18:01:20 +00:00
u8 size ;
u8 vcount ;
2013-07-25 06:58:45 +00:00
u16_le fcount ;
u32_le resident ;
2013-08-13 17:03:40 +00:00
u16_le vcountNew ;
u8 unknown1 ;
u8 unknown2 ;
2012-11-04 18:01:20 +00:00
} ;
2012-11-01 15:19:01 +00:00
2013-07-25 06:58:45 +00:00
u32_le * entPos = ( u32_le * ) Memory : : GetPointer ( modinfo - > libent ) ;
u32_le * entEnd = ( u32_le * ) 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-08-29 09:48:03 +00:00
u32 variableCount = ent - > size < = 4 ? ent - > vcount : std : : max ( ( u32 ) ent - > vcount , ( u32 ) ent - > vcountNew ) ;
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-09-07 20:02:55 +00:00
INFO_LOG ( LOADER , " 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-08-31 23:26:31 +00:00
if ( ent - > fcount + variableCount > 0 ) {
2013-05-25 22:14:34 +00:00
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-07-25 06:58:45 +00:00
u32_le * residentPtr = ( u32_le * ) Memory : : GetPointer ( ent - > resident ) ;
2013-08-13 17:03:40 +00:00
u32_le * exportPtr = residentPtr + ent - > fcount + variableCount ;
2013-05-23 05:12:11 +00:00
2013-08-21 15:34:16 +00:00
if ( ent - > size ! = 4 & & ent - > unknown1 ! = 0 & & ent - > unknown2 ! = 0 ) {
2013-08-13 23:22:22 +00:00
WARN_LOG_REPORT ( LOADER , " Unexpected export module entry size %d, vcountNew=%08x, unknown1=%08x, unknown2=%08x " , ent - > size , ent - > vcountNew , ent - > unknown1 , ent - > unknown2 ) ;
2013-08-01 07:38:34 +00:00
}
2013-08-31 23:26:31 +00:00
FuncSymbolExport func ;
strncpy ( func . moduleName , name , KERNELOBJECT_MAX_NAME_LENGTH ) ;
func . moduleName [ KERNELOBJECT_MAX_NAME_LENGTH ] = ' \0 ' ;
2013-05-23 05:12:11 +00:00
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 :
2013-08-31 23:26:31 +00:00
func . nid = nid ;
func . symAddr = exportAddr ;
module - > ExportFunc ( func ) ;
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-08-31 23:26:31 +00:00
VarSymbolExport var ;
strncpy ( var . moduleName , name , KERNELOBJECT_MAX_NAME_LENGTH ) ;
var . moduleName [ KERNELOBJECT_MAX_NAME_LENGTH ] = ' \0 ' ;
2013-08-13 17:03:40 +00:00
for ( u32 j = 0 ; j < variableCount ; j + + ) {
2013-05-23 05:12:11 +00:00
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-08-31 23:26:31 +00:00
var . nid = nid ;
var . symAddr = exportAddr ;
module - > ExportVar ( var ) ;
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 ;
2013-06-05 17:56:36 +00:00
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 ) ;
2013-06-05 17:56:36 +00:00
u32 magic ;
Module * module = __KernelLoadELFFromPtr ( elfData , PSP_GetDefaultLoadAddress ( ) , error_string , & magic ) ;
2013-04-08 19:46:41 +00:00
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!
2013-07-25 06:58:45 +00:00
u32_le version ;
2012-11-01 15:19:01 +00:00
memcpy ( & version , fileptr + 4 , 4 ) ;
2013-07-25 06:58:45 +00:00
u32_le offset0 , offsets [ 16 ] ;
2012-11-01 15:19:01 +00:00
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 ) ;
2013-06-05 17:56:36 +00:00
u32 magic = 0 ;
2013-11-14 10:43:09 +00:00
u8 * temp = 0 ;
if ( offsets [ 5 ] & 3 ) {
// Our loader does NOT like to load from an unaligned address on ARM!
size_t size = offsets [ 6 ] - offsets [ 5 ] ;
temp = new u8 [ size ] ;
memcpy ( temp , fileptr + offsets [ 5 ] , size ) ;
INFO_LOG ( LOADER , " Elf unaligned, aligning! " )
}
module = __KernelLoadELFFromPtr ( temp ? temp : fileptr + offsets [ 5 ] , PSP_GetDefaultLoadAddress ( ) , error_string , & magic ) ;
if ( temp ) {
delete [ ] temp ;
}
2012-11-01 15:19:01 +00:00
}
else
{
2013-06-05 17:56:36 +00:00
u32 magic = 0 ;
module = __KernelLoadELFFromPtr ( fileptr , PSP_GetDefaultLoadAddress ( ) , error_string , & magic ) ;
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 )
{
2014-01-12 21:37:31 +00:00
m - > nm . status = MODULE_STATUS_STARTED ;
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 ;
}
}
2013-07-14 15:34:06 +00:00
bool __KernelLoadExec ( const char * filename , u32 paramPtr , std : : string * error_string )
2012-11-01 15:19:01 +00:00
{
2013-07-14 09:07:24 +00:00
SceKernelLoadExecParam param ;
2013-07-14 15:34:06 +00:00
if ( paramPtr )
Memory : : ReadStruct ( paramPtr , & param ) ;
else
memset ( & param , 0 , sizeof ( SceKernelLoadExecParam ) ) ;
2013-07-15 16:18:03 +00:00
u8 * param_argp = 0 ;
u8 * param_key = 0 ;
2013-07-14 15:34:06 +00:00
if ( param . args > 0 ) {
2013-07-15 16:18:03 +00:00
u32 argpAddr = param . argp ;
param_argp = new u8 [ param . args ] ;
Memory : : Memcpy ( param_argp , argpAddr , param . args ) ;
2013-07-14 15:34:06 +00:00
}
2013-07-15 16:18:03 +00:00
if ( param . keyp ! = 0 ) {
u32 keyAddr = param . keyp ;
2013-07-21 20:36:42 +00:00
size_t keylen = strlen ( Memory : : GetCharPointer ( keyAddr ) ) + 1 ;
2013-07-15 16:18:03 +00:00
param_key = new u8 [ keylen ] ;
2013-07-21 20:36:42 +00:00
Memory : : Memcpy ( param_key , keyAddr , ( u32 ) keylen ) ;
2013-07-14 15:34:06 +00:00
}
2013-07-14 09:07:24 +00:00
2012-11-01 15:19:01 +00:00
// Wipe kernel here, loadexec should reset the entire system
2013-10-18 16:08:02 +00:00
if ( __KernelIsRunning ( ) )
{
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 ( ) ;
2013-11-28 23:34:41 +00:00
GPU_Reinitialize ( ) ;
2013-05-14 12:37:20 +00:00
}
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 ( ) ;
2013-07-15 16:18:03 +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 ) ;
2013-07-21 20:36:42 +00:00
* error_string = StringFromFormat ( " Could not find executable %s " , filename ) ;
2013-07-14 15:34:06 +00:00
if ( paramPtr ) {
2013-07-15 16:18:03 +00:00
if ( param_argp ) delete [ ] param_argp ;
if ( param_key ) delete [ ] param_key ;
2013-07-14 15:34:06 +00:00
}
2013-04-27 21:16:51 +00:00
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 ) ;
2013-08-23 06:23:48 +00:00
u8 * temp = new u8 [ ( int ) info . size + 0x01000000 ] ;
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-07-15 16:18:03 +00:00
if ( ! module | | module - > isFake ) {
2013-09-01 00:31:30 +00:00
if ( module ) {
2013-09-01 01:43:53 +00:00
module - > Cleanup ( ) ;
2013-05-09 11:14:19 +00:00
kernelObjects . Destroy < Module > ( module - > GetUID ( ) ) ;
2013-09-01 00:31:30 +00:00
}
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 ;
2013-07-14 15:34:06 +00:00
if ( paramPtr ) {
2013-07-15 16:18:03 +00:00
if ( param_argp ) delete [ ] param_argp ;
if ( param_key ) delete [ ] param_key ;
2013-07-14 15:34:06 +00:00
}
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 ;
2013-07-14 15:34:06 +00:00
if ( paramPtr )
2013-07-16 07:49:07 +00:00
__KernelStartModule ( module , param . args , ( const char * ) param_argp , & option ) ;
2013-07-14 09:07:24 +00:00
else
__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 ( ) ) ;
2013-07-14 15:34:06 +00:00
2013-07-15 16:18:03 +00:00
if ( param_argp ) delete [ ] param_argp ;
if ( param_key ) delete [ ] param_key ;
2013-11-02 22:47:43 +00:00
hleSkipDeadbeef ( ) ;
2012-11-01 15:19:01 +00:00
return true ;
}
2012-11-12 00:25:14 +00:00
int sceKernelLoadExec ( const char * filename , u32 paramPtr )
2012-11-01 15:19:01 +00:00
{
2013-06-16 04:30:48 +00:00
std : : string exec_filename = filename ;
PSPFileInfo info = pspFileSystem . GetFileInfo ( exec_filename ) ;
// If there's an EBOOT.BIN, redirect to that instead.
if ( info . exists & & endsWith ( exec_filename , " /BOOT.BIN " ) ) {
std : : string eboot_filename = exec_filename . substr ( 0 , exec_filename . length ( ) - strlen ( " BOOT.BIN " ) ) + " EBOOT.BIN " ;
PSPFileInfo eboot_info = pspFileSystem . GetFileInfo ( eboot_filename ) ;
if ( eboot_info . exists ) {
exec_filename = eboot_filename ;
info = eboot_info ;
}
2012-11-01 15:19:01 +00:00
}
2012-11-05 11:02:09 +00:00
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 ;
2013-06-16 04:30:48 +00:00
if ( ! size ) {
2012-11-05 11:02:09 +00:00
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
}
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( SCEMODULE , " sceKernelLoadExec(name=%s,...): loading %s " , filename , exec_filename . c_str ( ) ) ;
2012-11-01 15:19:01 +00:00
std : : string error_string ;
2013-07-14 09:07:24 +00:00
if ( ! __KernelLoadExec ( exec_filename . c_str ( ) , paramPtr , & error_string ) ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEMODULE , " sceKernelLoadExec failed: %s " , error_string . c_str ( ) ) ;
2013-06-16 04:22:28 +00:00
Core_UpdateState ( CORE_ERROR ) ;
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
2013-06-11 09:48:45 +00:00
for ( size_t i = 0 ; i < ARRAY_SIZE ( lieAboutSuccessModules ) ; i + + ) {
if ( ! strcmp ( name , lieAboutSuccessModules [ i ] ) ) {
INFO_LOG ( LOADER , " Tries to load module %s. We return a fake module. " , lieAboutSuccessModules [ i ] ) ;
Module * module = new Module ;
kernelObjects . Create ( module ) ;
2013-09-01 00:31:30 +00:00
loadedModules . insert ( module - > GetUID ( ) ) ;
2013-06-11 09:48:45 +00:00
memset ( & module - > nm , 0 , sizeof ( module - > nm ) ) ;
module - > isFake = true ;
return module - > GetUID ( ) ;
}
}
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 ) ;
2014-02-05 07:49:20 +00:00
if ( flags ! = 0 ) {
WARN_LOG_REPORT ( LOADER , " sceKernelLoadModule: unsupported flags: %08x " , 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 ) ;
2014-02-05 07:49:20 +00:00
WARN_LOG_REPORT ( LOADER , " sceKernelLoadModule: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d " , lmoption - > size , lmoption - > flags , lmoption - > position , lmoption - > access , lmoption - > mpiddata , lmoption - > mpidtext ) ;
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 ) ;
2013-06-05 17:56:36 +00:00
u32 magic ;
module = __KernelLoadELFFromPtr ( temp , 0 , & error_string , & magic ) ;
2012-11-05 17:03:02 +00:00
delete [ ] temp ;
pspFileSystem . CloseFile ( handle ) ;
2012-11-05 11:02:09 +00:00
if ( ! module ) {
2013-06-05 17:56:36 +00:00
if ( magic = = 0x46535000 ) {
ERROR_LOG ( LOADER , " Game tried to load an SFO as a module. Go figure? Magic = %08x " , magic ) ;
return - 1 ;
}
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 ) {
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " %i=sceKernelLoadModule(name=%s,flag=%08x,%08x,%08x,%08x,position = %08x) " ,
2012-11-05 11:02:09 +00:00
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 {
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " %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-08-30 18:13:59 +00:00
SceKernelSMOption smoption = { 0 } ;
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-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " 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 ;
2014-01-12 21:37:31 +00:00
} else if ( module - > nm . status = = MODULE_STATUS_STARTED ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEMODULE , " sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x) : already started " ,
2013-05-26 18:30:22 +00:00
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-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " 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-09-07 20:02:55 +00:00
WARN_LOG ( SCEMODULE , " sceKernelStartModule(): module has no start or entry func " ) ;
2014-01-12 21:37:31 +00:00
module - > nm . status = MODULE_STATUS_STARTED ;
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 } ;
2014-01-12 21:37:31 +00:00
module - > nm . status = MODULE_STATUS_STARTING ;
2013-05-26 17:54:11 +00:00
module - > waitingThreads . push_back ( mwt ) ;
2013-05-23 07:31:30 +00:00
}
else if ( entryAddr = = 0 )
{
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " 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 ) ;
2014-01-12 21:37:31 +00:00
module - > nm . status = MODULE_STATUS_STARTED ;
2013-05-23 07:31:30 +00:00
}
else
{
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEMODULE , " 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 )
{
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEMODULE , " sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): invalid module id " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
2013-05-26 18:30:22 +00:00
return error ;
}
if ( module - > isFake )
{
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " sceKernelStopModule(%08x, %08x, %08x, %08x, %08x) - faking " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
2013-05-26 18:30:22 +00:00
if ( returnValueAddr )
Memory : : Write_U32 ( 0 , returnValueAddr ) ;
return 0 ;
}
2014-01-12 21:37:31 +00:00
if ( module - > nm . status ! = MODULE_STATUS_STARTED )
2013-05-26 18:30:22 +00:00
{
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEMODULE , " sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): already stopped " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
2013-05-26 18:30:22 +00:00
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 )
2013-09-07 20:02:55 +00:00
WARN_LOG_REPORT ( SCEMODULE , " Stopping module with attr=%x, but options specify 0 " , attr ) ;
2013-05-26 18:30:22 +00:00
}
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 } ;
2014-01-12 21:37:31 +00:00
module - > nm . status = MODULE_STATUS_STOPPING ;
2013-05-26 18:30:22 +00:00
module - > waitingThreads . push_back ( mwt ) ;
}
else if ( stopFunc = = 0 )
{
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): no stop func, skipping " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
2014-01-12 21:37:31 +00:00
module - > nm . status = MODULE_STATUS_STOPPED ;
2013-05-26 18:30:22 +00:00
}
else
{
2013-09-07 20:02:55 +00:00
ERROR_LOG_REPORT ( SCEMODULE , " sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): bad stop func address " , moduleId , argSize , argAddr , returnValueAddr , optionAddr ) ;
2014-01-12 21:37:31 +00:00
module - > nm . status = MODULE_STATUS_STOPPED ;
2013-05-26 18:30:22 +00:00
}
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-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " 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
2013-09-01 01:43:53 +00:00
module - > Cleanup ( ) ;
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
}
2014-01-12 21:37:31 +00:00
u32 sceKernelStopUnloadSelfModuleWithStatus ( u32 exitCode , u32 argSize , u32 argp , u32 statusAddr , u32 optionAddr ) {
if ( loadedModules . size ( ) > 1 ) {
ERROR_LOG_REPORT ( SCEMODULE , " UNIMPL sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): game may have crashed " , exitCode , argSize , argp , statusAddr , optionAddr ) ;
SceUID moduleID = __KernelGetCurThreadModuleId ( ) ;
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 ( SCEMODULE , " sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): invalid module id " , exitCode , argSize , argp , statusAddr , optionAddr ) ;
return error ;
}
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 ( SCEMODULE , " 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 , argp ) ;
__KernelSetThreadRA ( threadID , NID_MODULERETURN ) ;
__KernelWaitCurThread ( WAITTYPE_MODULE , moduleID , 1 , 0 , false , " unloadstopped module " ) ;
const ModuleWaitingThread mwt = { __KernelGetCurThread ( ) , statusAddr } ;
module - > nm . status = MODULE_STATUS_UNLOADING ;
module - > waitingThreads . push_back ( mwt ) ;
} else if ( stopFunc = = 0 ) {
INFO_LOG ( SCEMODULE , " sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): no stop func " , exitCode , argSize , argp , statusAddr , optionAddr ) ;
sceKernelExitDeleteThread ( exitCode ) ;
module - > Cleanup ( ) ;
kernelObjects . Destroy < Module > ( moduleID ) ;
} else {
ERROR_LOG_REPORT ( SCEMODULE , " sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): bad stop func address " , exitCode , argSize , argp , statusAddr , optionAddr ) ;
sceKernelExitDeleteThread ( exitCode ) ;
module - > Cleanup ( ) ;
kernelObjects . Destroy < Module > ( moduleID ) ;
}
} else {
ERROR_LOG_REPORT ( SCEMODULE , " UNIMPL sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): game has likely crashed " , exitCode , argSize , argp , statusAddr , optionAddr ) ;
}
2013-05-20 00:54:14 +00:00
// 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.
2013-10-30 05:53:25 +00:00
hleSkipDeadbeef ( ) ;
2013-05-26 17:28:08 +00:00
__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 ) ;
2014-01-12 21:37:31 +00:00
if ( ! module ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG_REPORT ( SCEMODULE , " Returned from deleted module start/stop func " ) ;
2013-05-26 17:54:11 +00:00
return ;
}
// We can't be starting and stopping at the same time, so no need to differentiate.
2014-01-12 21:37:31 +00:00
if ( module - > nm . status = = MODULE_STATUS_STARTING )
module - > nm . status = MODULE_STATUS_STARTED ;
if ( module - > nm . status = = MODULE_STATUS_STOPPING )
module - > nm . status = MODULE_STATUS_STOPPED ;
for ( auto it = module - > waitingThreads . begin ( ) , end = module - > waitingThreads . end ( ) ; it < end ; + + it ) {
2013-05-26 17:54:11 +00:00
// Still waiting?
2013-09-07 17:51:11 +00:00
if ( HLEKernel : : VerifyWait ( it - > threadID , WAITTYPE_MODULE , leftModuleID ) )
2013-05-26 17:54:11 +00:00
{
2014-01-12 21:37:31 +00:00
if ( module - > nm . status = = MODULE_STATUS_UNLOADING ) {
// TODO: Maybe should maintain the exitCode?
sceKernelDeleteThread ( it - > threadID ) ;
} else {
if ( it - > statusPtr ! = 0 )
Memory : : Write_U32 ( exitStatus , it - > statusPtr ) ;
__KernelResumeThreadFromWait ( it - > threadID , 0 ) ;
}
2013-05-26 17:54:11 +00:00
}
}
module - > waitingThreads . clear ( ) ;
2014-01-12 21:37:31 +00:00
if ( module - > nm . status = = MODULE_STATUS_UNLOADING ) {
// TODO: Delete the waiting thread?
kernelObjects . Destroy < Module > ( leftModuleID ) ;
}
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 ;
2013-06-19 06:54:29 +00:00
kernelObjects . Iterate ( & __GetModuleIdByAddressIterator , & state ) ;
2013-07-08 01:24:53 +00:00
if ( state . result = = ( SceUID ) SCE_KERNEL_ERROR_UNKNOWN_MODULE )
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEMODULE , " sceKernelGetModuleIdByAddress(%08x): module not found " , moduleAddr )
2013-04-11 04:03:43 +00:00
else
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( SCEMODULE , " %x=sceKernelGetModuleIdByAddress(%08x) " , state . result , moduleAddr ) ;
2013-04-11 04:03:43 +00:00
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-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " sceKernelGetModuleId() " ) ;
2013-01-05 18:43:51 +00:00
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-09-07 20:02:55 +00:00
ERROR_LOG_REPORT ( SCEMODULE , " UNIMPL sceKernelFindModuleByName(%s) " , name ) ;
2013-08-29 08:26:54 +00:00
int index = GetModuleIndex ( name ) ;
if ( index = = - 1 )
return 0 ;
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-09-07 20:02:55 +00:00
ERROR_LOG ( SCEMODULE , " sceKernelLoadModuleByID(%08x, %08x, %08x): could not open file id " , id , flags , lmoptionPtr ) ;
2013-01-01 23:36:34 +00:00
return error ;
}
2014-02-05 07:49:20 +00:00
if ( flags ! = 0 ) {
WARN_LOG_REPORT ( LOADER , " sceKernelLoadModuleByID: unsupported flags: %08x " , flags ) ;
}
2013-01-01 23:36:34 +00:00
SceKernelLMOption * lmoption = 0 ;
if ( lmoptionPtr ) {
lmoption = ( SceKernelLMOption * ) Memory : : GetPointer ( lmoptionPtr ) ;
2014-02-05 07:49:20 +00:00
WARN_LOG_REPORT ( LOADER , " sceKernelLoadModuleByID: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d " , lmoption - > size , lmoption - > flags , lmoption - > position , lmoption - > access , lmoption - > mpiddata , lmoption - > mpidtext ) ;
2013-01-01 23:36:34 +00:00
}
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-06-05 17:56:36 +00:00
u32 magic ;
module = __KernelLoadELFFromPtr ( temp , 0 , & error_string , & magic ) ;
2013-01-01 23:36:34 +00:00
delete [ ] temp ;
if ( ! module ) {
2013-06-05 17:56:36 +00:00
// Some games try to load strange stuff as PARAM.SFO as modules and expect it to fail.
// This checks for the SFO magic number.
if ( magic = = 0x46535000 ) {
ERROR_LOG ( LOADER , " Game tried to load an SFO as a module. Go figure? Magic = %08x " , magic ) ;
return - 1 ;
}
2013-01-01 23:36:34 +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.
2013-06-05 17:56:36 +00:00
2013-01-01 23:36:34 +00:00
NOTICE_LOG ( LOADER , " Module %d is blacklisted or undecryptable - we lie about success " , id ) ;
return 1 ;
}
if ( lmoption ) {
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " %i=sceKernelLoadModuleByID(%d,flag=%08x,%08x,%08x,%08x,position = %08x) " ,
2013-01-01 23:36:34 +00:00
module - > GetUID ( ) , id , flags ,
lmoption - > size , lmoption - > mpidtext , lmoption - > mpiddata , lmoption - > position ) ;
} else {
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " %i=sceKernelLoadModuleByID(%d,flag=%08x,(...)) " , module - > GetUID ( ) , id , flags ) ;
2013-01-01 23:36:34 +00:00
}
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-09-07 20:02:55 +00:00
ERROR_LOG_REPORT ( SCEMODULE , " UNIMPL 0=sceKernelLoadModuleDNAS() " ) ;
2012-12-12 16:40:53 +00:00
return 0 ;
}
2013-12-27 08:18:33 +00:00
SceUID sceKernelLoadModuleBufferUsbWlan ( u32 size , u32 bufPtr , u32 flags , u32 lmoptionPtr )
{
2014-02-05 07:49:20 +00:00
if ( flags ! = 0 ) {
WARN_LOG_REPORT ( LOADER , " sceKernelLoadModuleBufferUsbWlan: unsupported flags: %08x " , flags ) ;
}
2013-12-27 08:18:33 +00:00
SceKernelLMOption * lmoption = 0 ;
if ( lmoptionPtr ) {
lmoption = ( SceKernelLMOption * ) Memory : : GetPointer ( lmoptionPtr ) ;
2014-02-05 07:49:20 +00:00
WARN_LOG_REPORT ( LOADER , " sceKernelLoadModuleBufferUsbWlan: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d " , lmoption - > size , lmoption - > flags , lmoption - > position , lmoption - > access , lmoption - > mpiddata , lmoption - > mpidtext ) ;
2013-12-27 08:18:33 +00:00
}
std : : string error_string ;
Module * module = 0 ;
u32 magic ;
module = __KernelLoadELFFromPtr ( Memory : : GetPointer ( bufPtr ) , 0 , & error_string , & magic ) ;
if ( ! module ) {
// Some games try to load strange stuff as PARAM.SFO as modules and expect it to fail.
// This checks for the SFO magic number.
if ( magic = = 0x46535000 ) {
ERROR_LOG ( LOADER , " Game tried to load an SFO as a module. Go figure? Magic = %08x " , magic ) ;
return - 1 ;
}
// 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 is blacklisted or undecryptable - we lie about success " ) ;
return 1 ;
}
if ( lmoption ) {
INFO_LOG ( SCEMODULE , " %i=sceKernelLoadModuleBufferUsbWlan(%x,%08x,flag=%08x,%08x,%08x,%08x,position = %08x) " ,
module - > GetUID ( ) , size , bufPtr , flags ,
lmoption - > size , lmoption - > mpidtext , lmoption - > mpiddata , lmoption - > position ) ;
} else {
INFO_LOG ( SCEMODULE , " %i=sceKernelLoadModuleBufferUsbWlan(%x,%08x,flag=%08x,(...)) " , module - > GetUID ( ) , size , bufPtr , flags ) ;
}
return module - > GetUID ( ) ;
}
2013-01-05 18:43:51 +00:00
u32 sceKernelQueryModuleInfo ( u32 uid , u32 infoAddr )
{
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEMODULE , " sceKernelQueryModuleInfo(%i, %08x) " , uid , infoAddr ) ;
2013-01-05 18:43:51 +00:00
u32 error ;
Module * module = kernelObjects . Get < Module > ( uid , error ) ;
if ( ! module )
return error ;
if ( ! Memory : : IsValidAddress ( infoAddr ) ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEMODULE , " sceKernelQueryModuleInfo(%i, %08x) - bad infoAddr " , uid , infoAddr ) ;
2013-01-05 18:43:51 +00:00
return - 1 ;
}
2013-12-09 08:45:54 +00:00
2013-12-17 07:47:34 +00:00
auto info = PSPPointer < ModuleInfo > : : Create ( infoAddr ) ;
2013-12-09 08:45:54 +00:00
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 ;
// Even if it's bigger, if it's not exactly 96, skip this extra data.
// Even if it's 0, the above are all written though.
if ( info - > size = = 96 ) {
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 ) ;
}
2013-01-05 18:43:51 +00:00
return 0 ;
}
2013-12-03 22:28:32 +00:00
u32 sceKernelGetModuleIdList ( u32 resultBuffer , u32 resultBufferSize , u32 idCountAddr )
2013-12-02 23:35:27 +00:00
{
2013-12-03 22:28:32 +00:00
ERROR_LOG ( SCEMODULE , " UNTESTED sceKernelGetModuleIdList(%08x, %i, %08x) " , resultBuffer , resultBufferSize , idCountAddr ) ;
int idCount = 0 ;
2013-12-04 15:56:33 +00:00
u32 resultBufferOffset = 0 ;
2013-12-03 22:28:32 +00:00
u32 error ;
for ( auto mod = loadedModules . begin ( ) , modend = loadedModules . end ( ) ; mod ! = modend ; + + mod ) {
Module * module = kernelObjects . Get < Module > ( * mod , error ) ;
if ( ! module - > isFake ) {
2013-12-31 05:37:19 +00:00
if ( resultBufferOffset < resultBufferSize ) {
2013-12-03 22:28:32 +00:00
Memory : : Write_U32 ( module - > GetUID ( ) , resultBuffer + resultBufferOffset ) ;
resultBufferOffset + = 4 ;
}
idCount + + ;
}
}
Memory : : Write_U32 ( idCount , idCountAddr ) ;
2013-12-02 23:35:27 +00:00
return 0 ;
}
2013-08-25 02:48:32 +00:00
u32 ModuleMgrForKernel_977de386 ( const char * name , u32 flags , u32 optionAddr )
{
2013-12-16 21:36:55 +00:00
WARN_LOG ( SCEMODULE , " ModuleMgrForKernel_977de386:Not support this patcher " ) ;
2013-08-25 02:48:32 +00:00
return sceKernelLoadModule ( name , flags , optionAddr ) ;
}
void ModuleMgrForKernel_50f0c1ec ( u32 moduleId , u32 argsize , u32 argAddr , u32 returnValueAddr , u32 optionAddr )
{
2013-12-16 21:36:55 +00:00
WARN_LOG ( SCEMODULE , " ModuleMgrForKernel_50f0c1ec:Not support this patcher " ) ;
2013-08-25 02:48:32 +00:00
sceKernelStartModule ( moduleId , argsize , argAddr , returnValueAddr , optionAddr ) ;
}
2013-08-31 19:35:24 +00:00
//fix for tiger x dragon
u32 ModuleMgrForKernel_a1a78c58 ( const char * name , u32 flags , u32 optionAddr )
{
2013-12-16 21:36:55 +00:00
WARN_LOG ( SCEMODULE , " ModuleMgrForKernel_a1a78c58:Not support this patcher " ) ;
2013-08-31 19:35:24 +00:00
return sceKernelLoadModule ( name , flags , optionAddr ) ;
}
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 " } ,
2013-08-29 06:15:13 +00:00
{ 0x50F0C1EC , & WrapV_UUUUU < sceKernelStartModule > , " sceKernelStartModule " , HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED } ,
2012-11-05 09:05:09 +00:00
{ 0xD675EBB8 , & sceKernelExitGame , " sceKernelSelfStopUnloadModule " } , //HACK
2013-08-29 06:15:13 +00:00
{ 0xd1ff982a , & WrapU_UUUUU < sceKernelStopModule > , " sceKernelStopModule " , HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED } ,
2013-01-05 18:43:51 +00:00
{ 0x2e0911aa , WrapU_U < sceKernelUnloadModule > , " sceKernelUnloadModule " } ,
2012-11-01 15:19:01 +00:00
{ 0x710F61B5 , 0 , " sceKernelLoadModuleMs " } ,
2013-12-27 08:18:33 +00:00
{ 0xF9275D98 , WrapI_UUUU < sceKernelLoadModuleBufferUsbWlan > , " sceKernelLoadModuleBufferUsbWlan " } , ///???
2012-11-01 15:19:01 +00:00
{ 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-12-02 23:35:27 +00:00
{ 0x644395e2 , WrapU_UUU < sceKernelGetModuleIdList > , " sceKernelGetModuleIdList " } ,
2013-05-29 02:39:28 +00:00
{ 0xf2d8d1b4 , & WrapU_CUU < sceKernelLoadModuleNpDrm > , " sceKernelLoadModuleNpDrm " } ,
2013-08-23 06:04:55 +00:00
{ 0xe4c4211c , 0 , " ModuleMgrForUser_E4C4211C " } ,
{ 0xfbe27467 , 0 , " ModuleMgrForUser_FBE27467 " } ,
2012-11-01 15:19:01 +00:00
} ;
2013-08-25 02:48:32 +00:00
const HLEFunction ModuleMgrForKernel [ ] =
{
{ 0x50f0c1ec , & WrapV_UUUUU < ModuleMgrForKernel_50f0c1ec > , " ModuleMgrForKernel_50f0c1ec " } , //Not sure right
{ 0x977de386 , & WrapU_CUU < ModuleMgrForKernel_977de386 > , " ModuleMgrForKernel_977de386 " } , //Not sure right
2013-08-31 19:35:24 +00:00
{ 0xa1a78c58 , & WrapU_CUU < ModuleMgrForKernel_a1a78c58 > , " ModuleMgrForKernel_a1a78c58 " } , //fix for tiger x dragon
2013-08-25 02:48:32 +00:00
} ;
2012-11-01 15:19:01 +00:00
void Register_ModuleMgrForUser ( )
{
RegisterModule ( " ModuleMgrForUser " , ARRAY_SIZE ( ModuleMgrForUser ) , ModuleMgrForUser ) ;
}
2013-08-25 02:48:32 +00:00
void Register_ModuleMgrForKernel ( )
{
RegisterModule ( " ModuleMgrForKernel " , ARRAY_SIZE ( ModuleMgrForKernel ) , ModuleMgrForKernel ) ;
2013-08-29 08:26:54 +00:00
} ;