Forum: PS2 Homebrew/Dev & Emu Scene - Topics relating to homebrew PS2 development and emulation. Stay current and up to date on the latest homebrew releases from the best devs on the scene.


The above video goes away if you are a member and logged in, so log in now!




 
Would you like to get all the new info from
PSX-Scene in your email each day?




Want to learn more about the team keeping you up to date with the latest scene news?

Read about them now!

Check out our Developer bios, too!

 


User Tag List

Thread: Documentation on what LoadExecPS2() can do (And the inner workings of rom0:EELOAD)
  

Results 1 to 3 of 3
  1. #1 Documentation on what LoadExecPS2() can do (And the inner workings of rom0:EELOAD) 
    SP193's Avatar
    SP193 is offline The fallen spartan...
    Join Date
    May 2009
    Location
    シンガポール
    Posts
    1,950
    Downloads
    0
    Uploads
    0
    Mentioned
    14 Post(s)
    Tagged
    3 Thread(s)
    Likes Given
    33
    Likes Received
    209
    This post by neme had my attention since quite a long time ago: http://psx-scene.com/forums/f153/fre...tml#post426801 (Free Vast Continues)

    As mentioned by neme one can use LoadExecPS2() to setup the PS2 for loading an ELF from other devices, with an argument list.

    rom0:EELOAD is the loader program that is loaded into 0x00082000 by LoadExecPS2() and is used to load and execute the specified program.

    On the SCPH-10000 (And all PS2 models), it clears and resets the EE. ExecPS2() is used within rom0:EELOAD, and was never documented in the Sony SDK, and was probably never expected to be used by external individuals (Hence why the "Protokernel" is "buggy" - it's because it expects a clean PS2 system).

    However, I've found that unlike what he stated (rom0:EELOAD is buggy and cannot load unencrypted ELFs), I found that it's actually perfectly working well.

    Code:
    /*
    	Filename:	rom0:EELOAD
    	Description:	EE executable Loader
    	BIOS version:	v1.01
    	Host console:	SCPH-10000
    	Date:		2012/04/13
    	Arguments:
    			argv[0]=<filename of ELF to load> or <"moduleload">
    			(Or if "moduleload" was specified as the first argument):
    			argv[1...n]= commands, where:
    					"-m <module to load>"			-> Loads a regular IOP module.
    					"-k <Encrypted module to load>"		-> Loads an encrypted IOP module.
    					"-x <Encrypted program to load>"	-> Loads and executes an encrypted EE program.
    
    			(Strings remaining in the argv[] array are arguments that are to be passed to the loaded program)
    
    	Other notes:	If no arguments are specified, it loads rom0:OSDSYS.
    */
    
    #include <sifrpc.h>
    #include <loadfile.h>
    #include <iopcontrol.h>
    #include <kernel.h>
    #include <dma_registers.h>
    
    static int var_000869a8;
    static t_ExecData ElfData;
    
    /* 0x000825a0 */
    static void func_000825a0(void){
    	/* TODO! Seems to be the same function that some Sony programs will call before doing anything. Probably not program-specific stuff. */
    }
    
    /* 0x000869a8 */
    static void func_00082640(void){
    	if(var_000869a8==0){
    		var_000869a8=1;
    		func_000825a0
    	}
    }
    
    /* 0x000820e8 */
    static void func_000820e8(void){
    	int i;
    
    	if(*DMA_REG_STAT&0x20){
    		SifSetDChain();
    		*DMA_REG_STAT=0x20;
    		while(*(volatile unsigned int *)0x1000f240&0x3000){
    			__asm("nop\nnop\nnop\n");
    		}
    
    		for(i=0x1000; i>0; i--) __asm("nop\nnop\nnop\nnop\nnop\n");
    	}
    }
    
    static const char IOPRP_path[8]="";
    
    /* 0x00082170 */
    static void func_00082170(void){
    	while((*EE_SBUS_SMFLAG&0x00040000)==0) __asm("nop\nnop\nnop\n");
    	*EE_SBUS_SMFLAG=0x00040000;
    }
    
    /* 0x000821b0 */
    static void ResetIOP(void){
    	SifIopReset(IOPRP_path, 0);
    	while(!SifIopSync()){};
    
    	func_00082170();
    }
    
    /* 0x000821e0 */
    static void func_000821e0(void){	/* Seems to have been written in asm. */
    FNC_000821e0:					#
    	lui		v0, $1000		# 000821e0:3c021000	v0=$10000000
    	ori		v0, v0, $f240		# 000821e4:3442f240	v0=reg_1000f240
    	lw		v1, $0000(v0)		# 000821e8:8c430000	v1=reg_1000f240
    	andi		v1, v1, $0020		# 000821ec:30630020	
    	beq		v1, zero, $00082254	# 000821f0:10600018	v __00082254
    	lui		v1, $0001		# 000821f4:3c030001	v1=$00010000
    __000821f8:					# 
    	di					# 000821f8:42000039	
    	sync.p					# 000821fc:0000040f	
    	mfc0		v0, Status		# 00082200:40026000	
    	and		v0, v0, v1		# 00082204:00431024	
    	nop					# 00082208:00000000	
    	bne		v0, zero, $000821f8	# 0008220c:1440fffa	^ __000821f8
    	nop					# 00082210:00000000	
    	mfc0		v1, Status		# 00082214:40036000	
    	lui		v0, $ffff		# 00082218:3c02ffff	v0=$ffff0000
    	ori		v0, v0, $ffe7		# 0008221c:3442ffe7	v0=$ffffffe7
    	and		v1, v1, v0		# 00082220:00621824	
    	mtc0		v1, Status		# 00082224:40836000	
    	sync.p					# 00082228:0000040f	
    	lui		v0, $bd00		# 0008222c:3c02bd00	v0=$bd000000
    	addiu		v1, zero, $0020		# 00082230:24030020	v1=$00000020
    	ori		v0, v0, $0040		# 00082234:34420040	v0=$bd000040
    	sw		v1, $0000(v0)		# 00082238:ac430000	[bd000040]
    	sync					# 0008223c:0000000f	
    	mfc0		v1, Status		# 00082240:40036000	
    	ori		v1, v1, $0010		# 00082244:34630010	
    	mtc0		v1, Status		# 00082248:40836000	
    	sync.p					# 0008224c:0000040f	
    	ei					# 00082250:42000038	
    __00082254:					# 
    	lui		v0, $1000		# 00082254:3c021000	v0=$10000000
    	ori		v0, v0, $e010		# 00082258:3442e010	v0=DMA_REG_STAT
    	lw		v1, $0000(v0)		# 0008225c:8c430000	v1=DMA_REG_STAT
    	andi		v1, v1, $0020		# 00082260:30630020	
    	beq		v1, zero, $00082274	# 00082264:10600003	v __00082274
    	addiu		v0, zero, $0020		# 00082268:24020020	v0=$00000020
    	lui		at, $1001		# 0008226c:3c011001	at=$10010000
    	sw		v0, $e010(at)		# 00082270:ac22e010	DMA_REG_STAT
    __00082274:					# 
    	jr		ra			# 00082274:03e00008	
    }
    
    /* 0x00082318 */
    static void BootError(const char *path){
    	char *argv[2];
    
    	SifExitRpc();
    
    	argv[0]="BootError";
    	argv[1]=path;
    
    	ExecOSD(2, argv);
    }
    
    /* 0x000822c0 */
    static void ExecExecutable(int argc, char **argv){
    	FlushCache(0);
    	SifExitRpc();
    
    	ExecPS2((void *)ElfData.epc, (void *)ElfData.gp, argc, argv);
    }
    
    static const char OSDSYS_path[]="rom0:OSDSYS";
    static const char *DefaultBootData[]={OSDSYS_path, 0x00000000};
    
    /* 0x00082280
    	Returns NULL if the argument doesn't contain the specified switch, otherwise, returns the first character after the switch.
    */
    static const char *IsSwitchCheck(const char *SwitchString, const char *cmd){
    	while(*SwitchString!='\0'){
    		if(*SwitchString!=*cmd) return NULL;
    		SwitchString++;
    		cmd++;
    	}
    
    	return cmd;
    }
    
    int main(int argc, char **argv){
    	const char *CommandString;
    	int value;
    
    	if(argc>=2){
    		argv++;
    		argc--;
    		func_000820e8();
    		ResetIOP();
    		func_000821e0();
    
    		SifInitRpc(0);
    
    		/* 0x000823cc */
    		if(IsSwitchCheck("moduleload", argv[0])!=NULL){
    			argc--;
    			argv++;
    
    			while(argc>0){
    				if((CommandString=IsSwitchCheck("-m ", argv[0]))!=NULL){
    					SifLoadModule(CommandString, 0, NULL);
    				}
    				else if((CommandString=IsSwitchCheck("-k ", argv[0]))!=NULL){
    					SifLoadModuleEncrypted(CommandString, 0, NULL);
    				}
    				else if((CommandString=IsSwitchCheck("-x ", argv[0]))!=NULL){
    					FlushCache(0);
    					if(SifLoadElfEncrypted(CommandString, &ElfData)<0){
    						BootError(CommandString);
    					}
    
    					ExecExecutable(argc, argv);
    				}
    				else break;
    
    				argc--;
    				argv++;
    			}
    		}
    
    		FlushCache(0);
    		if(SifLoadElf(argv[0], &ElfData)<0){
    			BootError(argv[0]);
    		}
    
    		ExecExecutable(argc, argv);
    	}
    
    	value=0;
    	func_00082170();
    	SifInitRpc(0);
    	FlushCache(0);
    	while(value==0){
    		if(SifLoadElf(DefaultBootData[0], &ElfData)<0){
    			value=1;
    		}
    	}
    
    	ExecExecutable(1, DefaultBootData[value]);
    
    	return 0;
    }
    So you can all see here that rom0:EELOAD basically calls SifLoadElf() again to load rom0:OSDSYS when it fails to load the ELF/KELF you tell it to. However, so far I've found that it usually results in a BSOD for some reason...

    The reason why neme couldn't load any unencrypted ELFs from his memory card was because of the prefix check that MODLOAD does before it loads any ELFs or IRX modules (Evil huh? ).

    Hence rom0:EELOAD attempts to bail out when it finds that it cannot load ELFs from the memory card, and fails to load rom0:OSDSYS for some reason.

    Usually, in homebrew programs, we get around that by patching MODLOAD (With sbv_patch_disable_prefix_check()).

    Newer consoles come with a version of rom0:EELOAD that supports the moduleload2 command, but I haven't worked on that yet.
    The SCPH-10000 and SCPH-15000 will get patched to load a copy of a newer version of rom0:EELOAD that (I think) supports the moduleload2 command too, but it's run from kernel memory (Where OPL stores it's IRX modules - 0x80030000).
    Unmodified SCPH-77006 with SM 3.6
    SCPH-39006 with M-chip modchip, SCPH-10281 NA and refurb Seagate 80GB HDD
    SCPH-10000 v1.00 with SCPH-10190 PCMCIA NA and SCPH-20400 HDD unit
    PS2ESDL v0.823B

    やっほー 汗がひかる♪
    Reply With Quote  

  2. #2  
    SilverBull's Avatar
    SilverBull is offline Member
    Join Date
    Nov 2008
    Posts
    16
    Downloads
    0
    Uploads
    0
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    Likes Given
    0
    Likes Received
    0
    Quote Originally Posted by SP193 View Post
    However, I've found that unlike what he stated (rom0:EELOAD is buggy and cannot load unencrypted ELFs), I found that it's actually perfectly working well.
    Its a security measure: never load unencrypted modules or ELFs from writable external devices like the HDD or mc. MODLOAD only allows it for trusted devices, which are the CDVD drive (authenticated by the MechaCon) and ROM. I think they didn't expect anyone to solder in another one with manipulated files...

    Quote Originally Posted by SP193 View Post
    Newer consoles come with a version of rom0:EELOAD that supports the moduleload2 command, but I haven't worked on that yet.
    The logic is similar, but the parameter to moduleload2 actually controls the program used to reset the IOP.
    Code:
    const char* a = IsSwitchCheck("moduleload2 ", argv[0]);
    const char* b = IsSwitchCheck("moduleload", argv[0]);
    if (a) {
      SifResetIop(a);
    } else {
      SifResetIop("rom0:UDNL rom0:EELOADCNF");
    }
    ...
    sceSifInitRpc(0);
    ...
    if (a || b) {
      for (argc--, argv++; argc != 0; argc--, argv++) {
        if ((p = IsSwitchCheck("-m ", argv[0])) != NULL) {
    ...
    This was from my first PS2 (ROMVER=0160EC20011004). Note that it uses EELOADCNF by default, which is not present on early machines.

    Quote Originally Posted by SP193 View Post
    The SCPH-10000 and SCPH-15000 will get patched to load a copy of a newer version of rom0:EELOAD that (I think) supports the moduleload2 command too, but it's run from kernel memory (Where OPL stores it's IRX modules - 0x80030000).
    I think its still a user-mode program (the SIF libraries do not work in kernel mode). What they do is this: copy a ROM file system image containing just the EELOAD replacement somewhere into kernel memory (sorry, I don't remember the address), then patch LoadExecPS2 to search that memory space instead of 0xBFC00000-0xBFC10000 for EELOAD.
    Reply With Quote  

  3. #3 Reverted edit. 
    SP193's Avatar
    SP193 is offline The fallen spartan...
    Join Date
    May 2009
    Location
    シンガポール
    Posts
    1,950
    Downloads
    0
    Uploads
    0
    Mentioned
    14 Post(s)
    Tagged
    3 Thread(s)
    Likes Given
    33
    Likes Received
    209
    Quote Originally Posted by SilverBull View Post
    Its a security measure: never load unencrypted modules or ELFs from writable external devices like the HDD or mc. MODLOAD only allows it for trusted devices, which are the CDVD drive (authenticated by the MechaCon) and ROM. I think they didn't expect anyone to solder in another one with manipulated files...
    Absolutely.

    But it totally limits what we can do with LoadExecPS2() at all. It would make it a lot easier to launch other software if it didn't have that limitations. Homebrew software like uLaunchELF wouldn't even need to have an embedded loader program at all.

    I can think of a new SBV patch - we copy the EELOAD program to 0x80030000 before patching it to call sbv_patch_disable_prefix_check() after it's IOP reset, and patch the EE kernel to load EELOAD from 0x80030000 to 0x00082000.

    It probably makes things cleaner for homebrew like uLaunchELF, since it wouldn't need to provide it's own loader.... but then we will run into a problem with devices that use the homebrew IOMANX filesystem manager (rom0:EELOAD accesses FILEIO, which interacts with rom0:IOMAN).

    I don't know why a standalone drop-in replacement for IOMAN wasn't created (As opposed to creating one that isn't meant to replace rom0:IOMAN, but to run aloneside it), or why IOMANX simply doesn't extend onto the exported functions by rom0:IOMAN.

    The earlier probably wasn't possible because it was not known how to reset the IOP with IOPRP images that are not stored on a disc... but why wasn't the latter done?

    Quote Originally Posted by SilverBull View Post
    The logic is similar, but the parameter to moduleload2 actually controls the program used to reset the IOP.
    Code:
    const char* a = IsSwitchCheck("moduleload2 ", argv[0]);
    const char* b = IsSwitchCheck("moduleload", argv[0]);
    if (a) {
      SifResetIop(a);
    } else {
      SifResetIop("rom0:UDNL rom0:EELOADCNF");
    }
    ...
    sceSifInitRpc(0);
    ...
    if (a || b) {
      for (argc--, argv++; argc != 0; argc--, argv++) {
        if ((p = IsSwitchCheck("-m ", argv[0])) != NULL) {
    ...
    This was from my first PS2 (ROMVER=0160EC20011004). Note that it uses EELOADCNF by default, which is not present on early machines.
    Thank you very much.

    That completes the purpose of this thread.

    Quote Originally Posted by SilverBull View Post
    I think its still a user-mode program (the SIF libraries do not work in kernel mode). What they do is this: copy a ROM file system image containing just the EELOAD replacement somewhere into kernel memory (sorry, I don't remember the address), then patch LoadExecPS2 to search that memory space instead of 0xBFC00000-0xBFC10000 for EELOAD.
    I made a mistake there. D:

    I should have said that the replacement EELOAD program is stored at 0x80030000 in kernel memory, and the EE kernel is patched to copy the new EELOAD program from that address to 0x00082000 for execution.

    If I remember correctly, the new EELOAD program is installed by encrypted osdsys.bin program that comes with the browser update for the SCPH-10000 and SCPH-15000.
    Last edited by SP193; 04-14-2012 at 12:25 PM. Reason: Corrected facts. If EELOAD can load modules from anywhere, IOMANX can be loaded freely.
    Unmodified SCPH-77006 with SM 3.6
    SCPH-39006 with M-chip modchip, SCPH-10281 NA and refurb Seagate 80GB HDD
    SCPH-10000 v1.00 with SCPH-10190 PCMCIA NA and SCPH-20400 HDD unit
    PS2ESDL v0.823B

    やっほー 汗がひかる♪
    Reply With Quote  

Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •