2012-01-21 21:57:41 +01:00
# include <stdlib.h>
# include <string.h>
# include <stdio.h>
2012-07-27 19:26:49 +02:00
# include <malloc.h>
2012-01-21 21:57:41 +01:00
2012-08-05 15:48:15 +02:00
# include "channel_launcher.h"
# include "gecko/gecko.h"
# include "loader/disc.h"
2012-08-12 23:26:24 +02:00
# include "loader/external_booter.hpp"
2012-08-05 15:48:15 +02:00
# include "loader/fs.h"
# include "loader/fst.h"
# include "loader/utils.h"
# include "unzip/lz77.h"
2012-08-12 23:26:24 +02:00
# include "types.h"
2012-01-21 21:57:41 +01:00
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-08-12 23:26:24 +02:00
void * dolchunkoffset [ 18 ] ;
u32 dolchunksize [ 18 ] ;
u32 dolchunkcount ;
2012-07-26 00:12:17 +02:00
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-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
2012-08-12 23:26:24 +02:00
ExternalBooter_ChannelSetup ( dolchunkoffset , dolchunksize , dolchunkcount , entry ) ;
WiiFlow_ExternalBooter ( vidMode , vipatch , countryString , patchVidMode , aspectRatio , 0 , TYPE_CHANNEL ) ;
2012-01-21 21:57:41 +01:00
return 0 ;
}
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 ] ;
2012-08-12 23:26:24 +02:00
gprintf ( " Moving section %u from offset %08x to %08x-%08x... \n " , i , dolfile - > section_pos [ i ] , dolchunkoffset [ dolchunkcount ] , ( u32 ) 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 ;
}
bool Identify_GenerateTik ( signed_blob * * outbuf , u32 * outlen )
{
2012-07-27 19:26:49 +02:00
signed_blob * buffer = ( signed_blob * ) memalign ( 32 , ALIGN32 ( STD_SIGNED_TIK_SIZE ) ) ;
if ( ! buffer )
return false ;
2012-01-21 21:57:41 +01:00
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-07-27 19:26:49 +02:00
free ( tmdBuffer ) ;
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-07-27 19:26:49 +02:00
free ( tmdBuffer ) ;
free ( tikBuffer ) ;
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-07-27 19:26:49 +02:00
free ( data ) ;
2012-01-21 21:57:41 +01:00
return NULL ;
}
2012-07-27 19:26:49 +02:00
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
}