2012-01-21 21:57:41 +01:00
# include "channel_launcher.h"
# include <stdlib.h>
# include <string.h>
# include <stdio.h>
# include "disc.h"
# include "patchcode.h"
# include "videopatch.h"
# include "fst.h"
# include "lz77.h"
# include "utils.h"
# include "fs.h"
# include "gecko.h"
# include "mem2.hpp"
2012-06-13 23:16:36 +02:00
# define STACK_ALIGN(type, name, cnt, alignment) \
u8 _al__ # # name [ ( ( sizeof ( type ) * ( cnt ) ) + ( alignment ) + \
( ( ( sizeof ( type ) * ( cnt ) ) % ( alignment ) ) > 0 ? ( ( alignment ) - \
( ( sizeof ( type ) * ( cnt ) ) % ( alignment ) ) ) : 0 ) ) ] ; \
type * name = ( type * ) ( ( ( u32 ) ( _al__ # # name ) ) + ( ( alignment ) - ( ( \
( u32 ) ( _al__ # # name ) ) & ( ( alignment ) - 1 ) ) ) )
2012-01-21 21:57:41 +01:00
GXRModeObj * __Disc_SelectVMode ( u8 videoselected , u64 chantitle ) ;
void __Disc_SetLowMem ( void ) ;
void __Disc_SetVMode ( void ) ;
void __Disc_SetTime ( void ) ;
void _unstub_start ( ) ;
2012-05-20 14:34:48 +02:00
u32 entryPoint ;
2012-01-21 21:57:41 +01:00
extern void __exception_closeall ( ) ;
typedef void ( * entrypoint ) ( void ) ;
2012-06-07 02:34:47 +02:00
typedef struct _dolheader
{
2012-01-21 21:57:41 +01:00
u32 section_pos [ 18 ] ;
u32 section_start [ 18 ] ;
u32 section_size [ 18 ] ;
u32 bss_start ;
u32 bss_size ;
u32 entry_point ;
u32 padding [ 7 ] ;
} __attribute__ ( ( packed ) ) dolheader ;
2012-05-20 14:34:48 +02:00
s32 BootChannel ( u32 entry , u64 chantitle , u32 ios , u8 vidMode , bool vipatch , bool countryString , u8 patchVidMode , int aspectRatio )
2012-01-21 21:57:41 +01:00
{
2012-05-20 14:34:48 +02:00
gprintf ( " Loading Channel... \n " ) ;
entryPoint = entry ;
2012-01-21 21:57:41 +01:00
/* Select an appropriate video mode */
GXRModeObj * vmode = __Disc_SelectVMode ( vidMode , chantitle ) ;
/* Set time */
__Disc_SetTime ( ) ;
2012-02-03 23:38:00 +01:00
2012-02-11 22:28:53 +01:00
/* Set low memory */
2012-01-21 21:57:41 +01:00
__Disc_SetLowMem ( ) ;
if ( hooktype ! = 0 )
ocarina_do_code ( ) ;
2012-01-27 14:59:36 +01:00
PatchChannel ( vidMode , vmode , vipatch , countryString , patchVidMode , aspectRatio ) ;
2012-01-21 21:57:41 +01:00
entrypoint appJump = ( entrypoint ) entryPoint ;
/* Set an appropriate video mode */
__Disc_SetVMode ( ) ;
2012-01-23 22:09:03 +01:00
// IOS Version Check
* ( vu32 * ) 0x80003140 = ( ( ios < < 16 ) ) | 0xFFFF ;
* ( vu32 * ) 0x80003188 = ( ( ios < < 16 ) ) | 0xFFFF ;
DCFlushRange ( ( void * ) 0x80003140 , 4 ) ;
DCFlushRange ( ( void * ) 0x80003188 , 4 ) ;
// Game ID Online Check
2012-06-07 02:34:47 +02:00
memset ( ( void * ) 0x80000000 , 0 , 4 ) ;
2012-01-23 22:09:03 +01:00
* ( vu32 * ) 0x80000000 = TITLE_LOWER ( chantitle ) ;
2012-06-07 02:34:47 +02:00
DCFlushRange ( ( void * ) 0x80000000 , 4 ) ;
2012-01-21 21:57:41 +01:00
gprintf ( " Jumping to entrypoint %08x \n " , entryPoint ) ;
2012-05-20 14:34:48 +02:00
/* Shutdown IOS subsystems */
u32 level = IRQ_Disable ( ) ;
__IOS_ShutdownSubsystems ( ) ;
__exception_closeall ( ) ;
/* Originally from tueidj - taken from NeoGamma (thx) */
* ( vu32 * ) 0xCC003024 = 1 ;
2012-01-21 21:57:41 +01:00
if ( entryPoint ! = 0x3400 )
{
2012-05-20 14:34:48 +02:00
if ( hooktype ! = 0 )
2012-01-21 21:57:41 +01:00
{
2012-06-07 02:34:47 +02:00
asm volatile (
2012-01-21 21:57:41 +01:00
" lis %r3, entryPoint@h \n "
" ori %r3, %r3, entryPoint@l \n "
" lwz %r3, 0(%r3) \n "
" mtlr %r3 \n "
" lis %r3, 0x8000 \n "
" ori %r3, %r3, 0x18A8 \n "
2012-02-05 19:38:57 +01:00
" nop \n "
2012-01-21 21:57:41 +01:00
" mtctr %r3 \n "
" bctr \n "
) ;
}
2012-05-20 14:34:48 +02:00
else
appJump ( ) ;
2012-01-21 21:57:41 +01:00
}
2012-05-20 14:34:48 +02:00
else if ( hooktype ! = 0 )
2012-01-21 21:57:41 +01:00
{
2012-06-07 02:34:47 +02:00
asm volatile (
2012-01-21 21:57:41 +01:00
" lis %r3, returnpoint@h \n "
" ori %r3, %r3, returnpoint@l \n "
" mtlr %r3 \n "
" lis %r3, 0x8000 \n "
" ori %r3, %r3, 0x18A8 \n "
2012-02-05 19:13:04 +01:00
" nop \n "
2012-01-21 21:57:41 +01:00
" mtctr %r3 \n "
" bctr \n "
" returnpoint: \n "
" bl DCDisable \n "
" bl ICDisable \n "
" li %r3, 0 \n "
" mtsrr1 %r3 \n "
" lis %r4, entryPoint@h \n "
" ori %r4,%r4,entryPoint@l \n "
" lwz %r4, 0(%r4) \n "
" mtsrr0 %r4 \n "
" rfi \n "
) ;
}
2012-05-20 14:34:48 +02:00
else
_unstub_start ( ) ;
IRQ_Restore ( level ) ;
2012-01-21 21:57:41 +01:00
return 0 ;
}
void * dolchunkoffset [ 18 ] ;
u32 dolchunksize [ 18 ] ;
u32 dolchunkcount ;
u32 LoadChannel ( u8 * buffer )
{
dolchunkcount = 0 ;
dolheader * dolfile = ( dolheader * ) buffer ;
2012-05-20 14:34:48 +02:00
if ( dolfile - > bss_start )
{
if ( ! ( dolfile - > bss_start & 0x80000000 ) )
dolfile - > bss_start | = 0x80000000 ;
memset ( ( void * ) dolfile - > bss_start , 0 , dolfile - > bss_size ) ;
DCFlushRange ( ( void * ) dolfile - > bss_start , dolfile - > bss_size ) ;
ICInvalidateRange ( ( void * ) dolfile - > bss_start , dolfile - > bss_size ) ;
}
int i ;
2012-01-23 23:01:23 +01:00
for ( i = 0 ; i < 18 ; i + + )
2012-01-21 21:57:41 +01:00
{
2012-05-24 00:09:11 +02:00
if ( ! dolfile - > section_size [ i ] )
continue ;
if ( dolfile - > section_pos [ i ] < sizeof ( dolheader ) )
continue ;
if ( ! ( dolfile - > section_start [ i ] & 0x80000000 ) )
dolfile - > section_start [ i ] | = 0x80000000 ;
2012-01-21 21:57:41 +01:00
dolchunkoffset [ dolchunkcount ] = ( void * ) dolfile - > section_start [ i ] ;
dolchunksize [ dolchunkcount ] = dolfile - > section_size [ i ] ;
gprintf ( " Moving section %u from offset %08x to %08x-%08x... \n " , i , dolfile - > section_pos [ i ] , dolchunkoffset [ dolchunkcount ] , dolchunkoffset [ dolchunkcount ] + dolchunksize [ dolchunkcount ] ) ;
2012-05-20 14:34:48 +02:00
memmove ( dolchunkoffset [ dolchunkcount ] , buffer + dolfile - > section_pos [ i ] , dolchunksize [ dolchunkcount ] ) ;
2012-01-21 21:57:41 +01:00
DCFlushRange ( dolchunkoffset [ dolchunkcount ] , dolchunksize [ dolchunkcount ] ) ;
2012-05-20 14:34:48 +02:00
ICInvalidateRange ( dolchunkoffset [ dolchunkcount ] , dolchunksize [ dolchunkcount ] ) ;
2012-01-21 21:57:41 +01:00
dolchunkcount + + ;
}
return dolfile - > entry_point ;
}
2012-01-27 14:59:36 +01:00
void PatchChannel ( u8 vidMode , GXRModeObj * vmode , bool vipatch , bool countryString , u8 patchVidModes , int aspectRatio )
2012-01-21 21:57:41 +01:00
{
bool hookpatched = false ;
2012-05-12 18:03:14 +02:00
u32 i ;
for ( i = 0 ; i < dolchunkcount ; i + + )
2012-01-21 21:57:41 +01:00
{
patchVideoModes ( dolchunkoffset [ i ] , dolchunksize [ i ] , vidMode , vmode , patchVidModes ) ;
if ( vipatch ) vidolpatcher ( dolchunkoffset [ i ] , dolchunksize [ i ] ) ;
if ( configbytes [ 0 ] ! = 0xCD ) langpatcher ( dolchunkoffset [ i ] , dolchunksize [ i ] ) ;
if ( countryString ) PatchCountryStrings ( dolchunkoffset [ i ] , dolchunksize [ i ] ) ;
2012-01-27 14:59:36 +01:00
if ( aspectRatio ! = - 1 ) PatchAspectRatio ( dolchunkoffset [ i ] , dolchunksize [ i ] , aspectRatio ) ;
2012-01-21 21:57:41 +01:00
if ( hooktype ! = 0 )
if ( dogamehooks ( dolchunkoffset [ i ] , dolchunksize [ i ] , true ) )
hookpatched = true ;
}
if ( hooktype ! = 0 & & ! hookpatched )
{
gprintf ( " Error: Could not patch the hook \n " ) ;
gprintf ( " Ocarina and debugger won't work \n " ) ;
}
}
bool Identify_GenerateTik ( signed_blob * * outbuf , u32 * outlen )
{
signed_blob * buffer = ( signed_blob * ) MEM2_alloc ( STD_SIGNED_TIK_SIZE ) ;
if ( ! buffer ) return false ;
memset ( buffer , 0 , STD_SIGNED_TIK_SIZE ) ;
sig_rsa2048 * signature = ( sig_rsa2048 * ) buffer ;
signature - > type = ES_SIG_RSA2048 ;
tik * tik_data = ( tik * ) SIGNATURE_PAYLOAD ( buffer ) ;
strcpy ( tik_data - > issuer , " Root-CA00000001-XS00000003 " ) ;
memset ( tik_data - > cidx_mask , 0xFF , 32 ) ;
* outbuf = buffer ;
* outlen = STD_SIGNED_TIK_SIZE ;
return true ;
}
2012-07-10 13:25:27 +02:00
bool Identify ( u64 titleid )
2012-01-21 21:57:41 +01:00
{
char filepath [ ISFS_MAXPATH ] ATTRIBUTE_ALIGN ( 32 ) ;
2012-05-20 14:34:48 +02:00
gprintf ( " Reading TMD... " ) ;
2012-01-21 21:57:41 +01:00
sprintf ( filepath , " /title/%08x/%08x/content/title.tmd " , TITLE_UPPER ( titleid ) , TITLE_LOWER ( titleid ) ) ;
u32 tmdSize ;
u8 * tmdBuffer = ISFS_GetFile ( ( u8 * ) & filepath , & tmdSize , - 1 ) ;
if ( tmdBuffer = = NULL | | tmdSize = = 0 )
{
2012-05-20 14:34:48 +02:00
gprintf ( " Failed! \n " ) ;
2012-01-21 21:57:41 +01:00
return false ;
}
2012-05-20 14:34:48 +02:00
gprintf ( " Success! \n " ) ;
2012-01-21 21:57:41 +01:00
u32 tikSize ;
signed_blob * tikBuffer = NULL ;
2012-05-20 14:34:48 +02:00
gprintf ( " Generating fake ticket... " ) ;
2012-01-21 21:57:41 +01:00
if ( ! Identify_GenerateTik ( & tikBuffer , & tikSize ) )
{
2012-05-20 14:34:48 +02:00
gprintf ( " Failed! \n " ) ;
2012-01-21 21:57:41 +01:00
return false ;
}
2012-05-20 14:34:48 +02:00
gprintf ( " Success! \n " ) ;
2012-01-21 21:57:41 +01:00
2012-05-20 14:34:48 +02:00
gprintf ( " Reading certs... " ) ;
2012-01-21 21:57:41 +01:00
sprintf ( filepath , " /sys/cert.sys " ) ;
u32 certSize ;
u8 * certBuffer = ISFS_GetFile ( ( u8 * ) & filepath , & certSize , - 1 ) ;
if ( certBuffer = = NULL | | certSize = = 0 )
{
2012-05-20 14:34:48 +02:00
gprintf ( " Failed! \n " ) ;
2012-05-13 19:25:26 +02:00
MEM2_free ( tmdBuffer ) ;
MEM2_free ( tikBuffer ) ;
2012-01-21 21:57:41 +01:00
return false ;
}
2012-05-20 14:34:48 +02:00
gprintf ( " Success! \n " ) ;
gprintf ( " ES_Identify \n " ) ;
2012-01-21 21:57:41 +01:00
s32 ret = ES_Identify ( ( signed_blob * ) certBuffer , certSize , ( signed_blob * ) tmdBuffer , tmdSize , tikBuffer , tikSize , NULL ) ;
if ( ret < 0 )
{
switch ( ret )
{
case ES_EINVAL :
gprintf ( " Error! ES_Identify (ret = %d;) Data invalid! \n " , ret ) ;
break ;
case ES_EALIGN :
gprintf ( " Error! ES_Identify (ret = %d;) Data not aligned! \n " , ret ) ;
break ;
case ES_ENOTINIT :
gprintf ( " Error! ES_Identify (ret = %d;) ES not initialized! \n " , ret ) ;
break ;
case ES_ENOMEM :
gprintf ( " Error! ES_Identify (ret = %d;) No memory! \n " , ret ) ;
break ;
default :
gprintf ( " Error! ES_Identify (ret = %d) \n " , ret ) ;
break ;
}
}
2012-05-13 19:25:26 +02:00
MEM2_free ( tmdBuffer ) ;
MEM2_free ( tikBuffer ) ;
MEM2_free ( certBuffer ) ;
2012-01-21 21:57:41 +01:00
return ret < 0 ? false : true ;
}
2012-05-24 00:09:11 +02:00
u8 * GetDol ( u64 title , u32 bootcontent )
2012-01-21 21:57:41 +01:00
{
char filepath [ ISFS_MAXPATH ] ATTRIBUTE_ALIGN ( 32 ) ;
sprintf ( filepath , " /title/%08x/%08x/content/%08x.app " , TITLE_UPPER ( title ) , TITLE_LOWER ( title ) , bootcontent ) ;
gprintf ( " Loading DOL: %s... " , filepath ) ;
u32 contentSize = 0 ;
u8 * data = ISFS_GetFile ( ( u8 * ) & filepath , & contentSize , - 1 ) ;
2012-02-03 23:38:00 +01:00
if ( data ! = NULL & & contentSize ! = 0 )
2012-01-21 21:57:41 +01:00
{
gprintf ( " Done! \n " ) ;
if ( isLZ77compressed ( data ) )
{
u8 * decompressed ;
u32 size = 0 ;
if ( decompressLZ77content ( data , contentSize , & decompressed , & size ) < 0 )
{
gprintf ( " Decompression failed \n " ) ;
2012-05-13 19:25:26 +02:00
MEM2_free ( data ) ;
2012-01-21 21:57:41 +01:00
return NULL ;
}
2012-05-13 19:25:26 +02:00
MEM2_free ( data ) ;
2012-01-21 21:57:41 +01:00
data = decompressed ;
}
return data ;
}
gprintf ( " Failed! \n " ) ;
return NULL ;
2012-05-13 17:13:33 +02:00
}