/* menu.c * * Triiforce mod by Marc * * Copyright (c) 2009 The Lemon Man, Nicksasa & WiiPower * * Distributed under the terms of the GNU General Public License (v2) * See http://www.gnu.org/licenses/gpl-2.0.txt for more info. * *********************************************/ #include #include #include #include #include #include #include #include //for network #include #include //for mkdir #include "tools.h" #include "lz77.h" #include "config.h" #include "patch.h" #include "codes/codes.h" #include "codes/patchcode.h" #include "nand.h" #include "fat_mine.h" #include "video.h" #include "sonido.h" #include "menu.h" #include "fat.h" // Constants #define ARROWS_X 24 #define ARROWS_Y 210 #define ARROWS_WIDTH 20 #define MIGHTY_PATH "fat:/config/mighty/" #define IMAGES_PREFIX "channels" #define MIGHTY_CONFIG_FILE "mighty_channels.cfg" #define MAXGAMES 800 #define EMPTY -1 #define BLACK 0x000000FF #define YELLOW 0xFFFF00FF #define WHITE 0xFFFFFFFF #define ORANGE 0xeab000ff // Variables for MIGHTY static char tempString[128]; static int nandMode=0; extern GXRModeObj *vmode; extern u32* framebuffer; const u8 COLS[]={3, 4}; #define ROWS 3 const u8 FIRSTCOL[]={136, 112}; #define FIRSTROW 96 const u8 SEPARACIONX[]={180, 136}; #define SEPARACIONY 112 const u8 ANCHOIMAGEN[]={154, 116}; #define ALTOIMAGEN 90 u8 Video_Mode; u32 entryPoint; void* dolchunkoffset[64]; //TODO: variable size u32 dolchunksize[64]; //TODO: variable size u32 dolchunkcount; void _unstub_start(); typedef void (*entrypoint) (void); typedef struct _dolheader{ u32 text_pos[7]; u32 data_pos[11]; u32 text_start[7]; u32 data_start[11]; u32 text_size[7]; u32 data_size[11]; u32 bss_start; u32 bss_size; u32 entry_point; } dolheader; bool __Check_HBC(void){ u32 *stub = (u32 *)0x80001800; // Check HBC stub if (*stub) return true; return false; } s32 check_dol(u64 titleid, char *out, u16 bootcontent){ s32 cfd; s32 ret; u32 num; dirent_t *list; char contentpath[ISFS_MAXPATH]; char path[ISFS_MAXPATH]; int cnt = 0; u8 LZ77_0x10 = 0x10; u8 LZ77_0x11 = 0x11; u8 *decompressed; u8 *compressed; u32 size_out = 0; u32 decomp_size = 0; u8 *buffer = memalign(32, 32); if (buffer == NULL){ printf("Out of memory\n"); return -1; } u8 check[6] = {0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; sprintf(contentpath, "/title/%08x/%08x/content", TITLE_UPPER(titleid), TITLE_LOWER(titleid)); ret = getdir(contentpath, &list, &num); if (ret < 0){ printf("Reading folder of the title failed\n"); free(buffer); return ret; } for(cnt=0; cnt < num; cnt++){ if ((strstr(list[cnt].name, ".app") != NULL || strstr(list[cnt].name, ".APP") != NULL) && (strtol(list[cnt].name, NULL, 16) != bootcontent)){ memset(buffer, 0x00, 32); sprintf(path, "/title/%08x/%08x/content/%s", TITLE_UPPER(titleid), TITLE_LOWER(titleid), list[cnt].name); cfd = ISFS_Open(path, ISFS_OPEN_READ); if (cfd < 0) { printf("ISFS_Open for %s failed %d\n", path, cfd); continue; } ret = ISFS_Read(cfd, buffer, 32); if (ret < 0) { printf("ISFS_Read for %s failed %d\n", path, ret); ISFS_Close(cfd); continue; } ISFS_Close(cfd); if (buffer[0] == LZ77_0x10 || buffer[0] == LZ77_0x11) { if (buffer[0] == LZ77_0x10) { printf("Found LZ77 0x10 compressed content --> %s\n", list[cnt].name); } else { printf("Found LZ77 0x11 compressed content --> %s\n", list[cnt].name); } printf("This is most likely the main DOL, decompressing for checking\n"); ret = read_file(path, &compressed, &size_out); if (ret < 0) { printf("Reading file failed\n"); free(list); free(buffer); return ret; } printf("read file\n"); ret = decompressLZ77content(compressed, 32, &decompressed, &decomp_size); if (ret < 0) { printf("Decompressing failed\n"); free(list); free(buffer); return ret; } memcpy(buffer, decompressed, 8); } ret = memcmp(buffer, check, 6); if(ret == 0) { printf("Found DOL --> %s\n", list[cnt].name); sprintf(out, "%s", path); free(buffer); free(list); return 0; } } } free(buffer); free(list); printf("No .dol found\n"); return -1; } void patch_dol(bool bootcontent){ int i; bool hookpatched = false; for (i=0;i < dolchunkcount;i++) { if (!bootcontent){ if (languageoption != -1){ patch_language(dolchunkoffset[i], dolchunksize[i], languageoption); } if (videopatchoption != 0){ search_video_modes(dolchunkoffset[i], dolchunksize[i]); patch_video_modes_to(vmode, videopatchoption); } } if (hooktypeoption != 0){ // Before this can be done, the codehandler needs to be in memory, and the code to patch needs to be in the right pace if (dochannelhooks(dolchunkoffset[i], dolchunksize[i], bootcontent)){ hookpatched = true; } } } if (hooktypeoption != 0 && !hookpatched){ printf("Error: Could not patch the hook\n"); printf("Ocarina and debugger won't work\n"); sleep(5); } } u32 load_dol(u8 *buffer){ dolchunkcount = 0; dolheader *dolfile; dolfile = (dolheader *)buffer; printf("Entrypoint: %08x\n", dolfile->entry_point); printf("BSS: %08x, size = %08x(%u)\n", dolfile->bss_start, dolfile->bss_size, dolfile->bss_size); memset((void *)dolfile->bss_start, 0, dolfile->bss_size); DCFlushRange((void *)dolfile->bss_start, dolfile->bss_size); printf("BSS cleared\n"); u32 doloffset; u32 memoffset; u32 restsize; u32 size; int i; for (i = 0; i < 7; i++){ if(dolfile->text_pos[i] < sizeof(dolheader)) continue; dolchunkoffset[dolchunkcount] = (void *)dolfile->text_start[i]; dolchunksize[dolchunkcount] = dolfile->text_size[i]; dolchunkcount++; doloffset = (u32)buffer + dolfile->text_pos[i]; memoffset = dolfile->text_start[i]; restsize = dolfile->text_size[i]; printf("Moving text section %u from %08x to %08x-%08x...", i, dolfile->text_pos[i], dolfile->text_start[i], dolfile->text_start[i]+dolfile->text_size[i]); fflush(stdout); while (restsize > 0){ if (restsize > 2048){ size = 2048; }else{ size = restsize; } restsize -= size; ICInvalidateRange ((void *)memoffset, size); memcpy((void *)memoffset, (void *)doloffset, size); DCFlushRange((void *)memoffset, size); doloffset += size; memoffset += size; } printf("done\n"); fflush(stdout); } for(i = 0; i < 11; i++){ if(dolfile->data_pos[i] < sizeof(dolheader)) continue; dolchunkoffset[dolchunkcount] = (void *)dolfile->data_start[i]; dolchunksize[dolchunkcount] = dolfile->data_size[i]; dolchunkcount++; doloffset = (u32)buffer + dolfile->data_pos[i]; memoffset = dolfile->data_start[i]; restsize = dolfile->data_size[i]; printf("Moving data section %u from %08x to %08x-%08x...", i, dolfile->data_pos[i], dolfile->data_start[i], dolfile->data_start[i]+dolfile->data_size[i]); fflush(stdout); while (restsize > 0){ if (restsize > 2048){ size = 2048; }else{ size = restsize; } restsize -= size; ICInvalidateRange ((void *)memoffset, size); memcpy((void *)memoffset, (void *)doloffset, size); DCFlushRange((void *)memoffset, size); doloffset += size; memoffset += size; } printf("done\n"); fflush(stdout); } return dolfile->entry_point; } s32 search_and_read_dol(u64 titleid, u8 **contentBuf, u32 *contentSize, bool skip_bootcontent){ char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(0x20); int ret; u16 bootindex; u16 bootcontent; bool bootcontent_loaded; u8 *tmdBuffer = NULL; u32 tmdSize; tmd_content *p_cr; printf("Reading TMD..."); sprintf(filepath, "/title/%08x/%08x/content/title.tmd", TITLE_UPPER(titleid), TITLE_LOWER(titleid)); ret = read_file(filepath, &tmdBuffer, &tmdSize); if (ret < 0) { printf("Reading TMD failed\n"); return ret; } printf("done\n"); bootindex = ((tmd *)SIGNATURE_PAYLOAD((signed_blob *)tmdBuffer))->boot_index; p_cr = TMD_CONTENTS(((tmd *)SIGNATURE_PAYLOAD((signed_blob *)tmdBuffer))); bootcontent = p_cr[bootindex].cid; free(tmdBuffer); // Write bootcontent to filepath and overwrite it in case another .dol is found sprintf(filepath, "/title/%08x/%08x/content/%08x.app", TITLE_UPPER(titleid), TITLE_LOWER(titleid), bootcontent); if (skip_bootcontent) { bootcontent_loaded = false; printf("Searching for main DOL...\n"); ret = check_dol(titleid, filepath, bootcontent); if (ret < 0) { printf("Searching for main.dol failed\n"); printf("Press any button to load NAND loader instead...\n"); bootcontent_loaded = true; } } else { bootcontent_loaded = true; } printf("Loading DOL: %s\n", filepath); ret = read_file(filepath, contentBuf, contentSize); if (ret < 0) { printf("Reading .dol failed\n"); return ret; } if (isLZ77compressed(*contentBuf)) { u8 *decompressed; ret = decompressLZ77content(*contentBuf, *contentSize, &decompressed, contentSize); if (ret < 0) { printf("Decompression failed\n"); free(*contentBuf); return ret; } free(*contentBuf); *contentBuf = decompressed; } if(bootcontent_loaded){ return 1; }else{ return 0; } } void determineVideoMode(u64 titleid){ if (videooption == 0 || videooption == 1) { // Get rmode and Video_Mode for system settings first u32 tvmode = CONF_GetVideo(); // Attention: This returns &TVNtsc480Prog for all progressive video modes vmode = VIDEO_GetPreferredMode(0); switch (tvmode) { case CONF_VIDEO_PAL: if (CONF_GetEuRGB60() > 0) { Video_Mode = VI_EURGB60; } else { Video_Mode = VI_PAL; } break; case CONF_VIDEO_MPAL: Video_Mode = VI_MPAL; break; case CONF_VIDEO_NTSC: default: Video_Mode = VI_NTSC; } // Overwrite rmode and Video_Mode when Default Video Mode is selected and Wii region doesn't match the channel region u32 low; low = TITLE_LOWER(titleid); char Region = low % 256; if (*(char *)&low != 'W') // Don't overwrite video mode for WiiWare { switch (Region) { case 'P': case 'D': case 'F': case 'X': case 'Y': if (CONF_GetVideo() != CONF_VIDEO_PAL) { Video_Mode = VI_EURGB60; if (CONF_GetProgressiveScan() > 0 && VIDEO_HaveComponentCable()) { vmode = &TVNtsc480Prog; // This seems to be correct! } else { vmode = &TVEurgb60Hz480IntDf; } } break; case 'E': case 'J': case 'T': if (CONF_GetVideo() != CONF_VIDEO_NTSC) { Video_Mode = VI_NTSC; if (CONF_GetProgressiveScan() > 0 && VIDEO_HaveComponentCable()) { vmode = &TVNtsc480Prog; } else { vmode = &TVNtsc480IntDf; } } } } } else { if (videooption == 2){ vmode = &TVPal528IntDf; } else if (videooption == 3){ vmode = &TVEurgb60Hz480IntDf; } else if (videooption == 4){ vmode = &TVNtsc480IntDf; } else if (videooption == 5){ vmode = &TVNtsc480Prog; } Video_Mode = (vmode->viTVMode) >> 2; } } void setVideoMode(){ *(u32 *)0x800000CC = Video_Mode; DCFlushRange((void*)0x800000CC, sizeof(u32)); // Overwrite all progressive video modes as they are broken in libogc if (videomode_interlaced(vmode) == 0){ vmode = &TVNtsc480Prog; } VIDEO_Configure(vmode); VIDEO_SetNextFramebuffer(framebuffer); VIDEO_SetBlack(FALSE); VIDEO_Flush(); VIDEO_WaitVSync(); if (vmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync(); } #define MAXAPPLOADERGAMES 7 const char games[MAXAPPLOADERGAMES][4]={ "WAL", //ArtSyle: light trax "WDH", //ArtSyle: Rotohex "WOB", //ArtSyle: ORBIENT "WPR", //ArtSyle: CUBELLO "WA8", //ArtSyle: Penta Tentacles "WB7", //Midnight Pool "WSP" //Pokemon Rumble }; bool checkApploaderGame(const char* id){ int i; for(i=0; iidInt)); if(memcmp(game->id, "WTR", 3)==0 || memcmp(game->id, "W8C", 3)==0 || memcmp(game->id, "WVB", 3)==0){ //Bit Trip BEAT/CORE/VOID Fat_MakeDir(dataPath); ret+=__CreateNullFile(dataPath, "banner.bin", 61600); ret+=__CreateNullFile(dataPath, "savefile.dat", 512); }else if(memcmp(game->id, "WRU", 3)==0){ //Bit Trip RUNNER Fat_MakeDir(dataPath); ret+=__CreateNullFile(dataPath, "banner.bin", 61600); ret+=__CreateNullFile(dataPath, "savefile.dat", 1024); }else if(memcmp(game->id, "WBF", 3)==0){ //Bit Trip FATE Fat_MakeDir(dataPath); ret+=__CreateNullFile(dataPath, "banner.bin", 61600); ret+=__CreateNullFile(dataPath, "savefile.dat", 192); }else if(memcmp(game->id, "WTF", 3)==0){ //Bit Trip FLUX Fat_MakeDir(dataPath); ret+=__CreateNullFile(dataPath, "banner.bin", 61600); ret+=__CreateNullFile(dataPath, "savefile.dat", 160); } return ret; } void __Start_Game(title game, int ios, int mode) { nandMode = mode; if(nandMode==EMU_USB) Fat_Mount(USB); else Fat_Mount(SD); int ret = 0; entrypoint appJump; u32 requested_ios; u8 *dolbuffer; u32 dolsize; bool bootcontentloaded; printf("Setting game info...\n"); printf("GameID: %08x\n", TITLE_LOWER(game.idInt)); u64 titleid=game.idInt; videooption=game.videoMode; videopatchoption=game.videoPatch; languageoption=game.language-1; hooktypeoption=game.hooktype; ocarinaoption=game.ocarina; debuggeroption=game.debugger; bootmethodoption=game.bootMethod; printf("Check savegame...\n"); if(nandMode!=REAL_NAND){ ret=checkNeededSave(&game); } //Unmount FAT Fat_Unmount(); //Initialize NAND if(nandMode!=REAL_NAND){ ret=Enable_Emu(nandMode); if(ret<0){ printf("ERROR: I can't enable NAND emulator (ret=%d).\n", ret); goto out; } } ISFS_Initialize(); ret = search_and_read_dol(titleid, &dolbuffer, &dolsize, (bootmethodoption == 0)); if (ret < 0){ printf(".dol loading failed\n"); return; } bootcontentloaded = (ret == 1); determineVideoMode(titleid); entryPoint = load_dol(dolbuffer); free(dolbuffer); printf(".dol loaded\n"); ret = identify(titleid, &requested_ios); if (ret < 0) { printf("Identify failed\n"); return; } ISFS_Deinitialize(); // Set the clock settime(secs_to_ticks(time(NULL) - 946684800)); if (entryPoint != 0x3400){ printf("Setting bus speed\n"); *(u32*)0x800000F8 = 0x0E7BE2C0; printf("Setting cpu speed\n"); *(u32*)0x800000FC = 0x2B73A840; DCFlushRange((void*)0x800000F8, 0xFF); } // Remove 002 error printf("Fake IOS Version(%u)\n", requested_ios); *(u16 *)0x80003140 = requested_ios; *(u16 *)0x80003142 = 0xffff; *(u16 *)0x80003188 = requested_ios; *(u16 *)0x8000318A = 0xffff; DCFlushRange((void*)0x80003140, 4); DCFlushRange((void*)0x80003188, 4); /*ret = ES_SetUID(titleid); if (ret < 0){ printf("ES_SetUID failed %d", ret); return; }*/ printf("ES_SetUID successful\n"); if(hooktypeoption != 0){ do_codes(titleid); } patch_dol(bootcontentloaded); printf("Loading complete, booting...\n"); appJump = (entrypoint)entryPoint; //sleep(5); setVideoMode(); //---GREENSCREEN FIX--- VIDEO_Configure(vmode); VIDEO_SetNextFramebuffer(framebuffer); VIDEO_SetBlack(TRUE); VIDEO_Flush(); VIDEO_WaitVSync(); //--------------------- SYS_ResetSystem(SYS_SHUTDOWN, 0, 0); if (entryPoint != 0x3400) { if (hooktypeoption != 0) { __asm__( "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" "mtctr %r3\n" "bctr\n" ); } else { appJump(); } } else { if (hooktypeoption != 0) { __asm__( "lis %r3, returnpoint@h\n" "ori %r3, %r3, returnpoint@l\n" "mtlr %r3\n" "lis %r3, 0x8000\n" "ori %r3, %r3, 0x18A8\n" "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" ); }else{ _unstub_start(); } } out: printf("ret=%d\n", ret); return; } #define CONFIGITEMS 7 int __Config_Game(void){ //Obtener informacion del juego //title *config = NULL; //char* gameId=config->id; /*u32 optioncount[CONFIGITEMS]={8,4,11,8,3,2,2}; u32 optionselected[CONFIGITEMS] = {config->videoMode, config->videoPatch, config->language, config->hooktype, config->ocarina, config->debugger, config->bootMethod}; char *videooptions[8]={"Default Video Mode", "Force NTSC480i", "Force NTSC480p", "Force PAL480i", "Force PAL480p", "Force PAL576i", "Force MPAL480i", "Force MPAL480p"}; char *videopatchoptions[4]={"No Video patches", "Smart Video patching", "More Video patching", "Full Video patching" }; char *languageoptions[11]={"Default Language", "Japanese", "English", "German", "French", "Spanish", "Italian", "Dutch", "S. Chinese", "T. Chinese", "Korean"}; char *hooktypeoptions[8]={"No Ocarina&debugger", "Hooktype: VBI", "Hooktype: KPAD", "Hooktype: Joypad", "Hooktype: GXDraw", "Hooktype: GXFlush", "Hooktype: OSSleepThread", "Hooktype: AXNextFrame"}; char *ocarinaoptions[3]={"No Ocarina", "Ocarina from SD", "Ocarina from USB"}; char *debuggeroptions[2]={"No debugger", "Debugger enabled"}; char *bootmethodoptions[2]={"Normal boot method", "Load apploader"};*/ return MENU_SELECT_GAME; } int __Update_File_From_Real_Nand(char* filepath){ u8 *inBuffer = NULL; u32 inSize; int ret=0; //ISFS init ret=ISFS_Initialize(); if(ret<0){ return ret; } ret=read_file(filepath, &inBuffer, &inSize); ISFS_Deinitialize(); if(ret<0){ return ret; } sprintf(tempString, "fat:/%s/%s", Get_Path(), filepath); ret=Fat_SaveFile(tempString, (void *)&inBuffer, inSize); return ret; }