#include #include #include #include #include "config.h" #include "patches.h" #include "video.h" #include "wpad.h" #include "tools.h" /* DOL header structure */ typedef struct { u32 textoff[7]; u32 dataoff[11]; u8 *textmem[7]; u8 *datamem[11]; u32 textsize[7]; u32 datasize[11]; u8 *bssmem; u32 bsssize; u32 entry; u32 unused[7]; } dolheader; /* Entry pointer */ typedef void (*dolentry)(void); /* Constants */ #define DOL_INDEX 1 void __Loader_SetLowMem(void) { /* Setup low memory */ *(vu32*)0x800000F8 = 0x0E7BE2C0; *(vu32*)0x800000FC = 0x2B73A840; /* Flush cache */ DCFlushRange((void *)(0x80000000), 0x3F00); // Set the clock settime(secs_to_ticks(time(NULL) - 946684800)); // Remove 002 error (set to IOS 53) *(u16 *)0x80003140 = 0x0035; *(u16 *)0x80003142 = 0xffff; *(u16 *)0x80003188 = 0x0035; *(u16 *)0x8000318A = 0xffff; DCFlushRange((void*)0x80003140, 4); DCFlushRange((void*)0x80003188, 4); } void __Loader_SetVMode(u64 tid) { GXRModeObj *vmode_ptr = NULL; u32 vmode_reg; u32 progressive, tvmode; /* Get video mode configuration */ progressive = (CONF_GetProgressiveScan() > 0) && VIDEO_HaveComponentCable(); tvmode = CONF_GetVideo(); /* Select video mode */ switch(tid & 0xFF) { /* PAL */ case 'P': vmode_reg = (CONF_GetEuRGB60() > 0) ? 5 : 1; if (tvmode != CONF_VIDEO_PAL) { vmode_reg = 5; vmode_ptr = &TVNtsc480IntDf; } break; /* NTSC or unknown */ case 'E': case 'J': vmode_reg = 0; if (tvmode != CONF_VIDEO_NTSC) vmode_ptr = &TVEurgb60Hz480IntDf; break; default: vmode_reg = 0; } /* Override video mode */ if (loaderCfg.forcePal50) { vmode_reg = 1; vmode_ptr = &TVPal528IntDf; } if (loaderCfg.forcePal60) { vmode_reg = 5; vmode_ptr = &TVEurgb60Hz480IntDf; } if (loaderCfg.forceNtsc) { vmode_reg = 0; vmode_ptr = &TVNtsc480IntDf; } if (loaderCfg.forceHdtv) { vmode_reg = 0; vmode_ptr = &TVNtsc480Prog; } /* Set video mode register */ *(vu32 *)0x800000CC = vmode_reg; /* Set video mode */ if (vmode_ptr) { /* If progressive available, use it */ if (progressive) vmode_ptr = &TVNtsc480Prog; Video_Configure(vmode_ptr); Video_Clear(COLOR_BLACK); } // Anti-green screen fix VIDEO_SetBlack(TRUE); VIDEO_Flush(); VIDEO_WaitVSync(); } void __Loader_PatchDol(u8 *buffer, u32 len) { struct config *cfg = &loaderCfg; /* Video mode patching */ if (cfg->patchVmode) Patch_VideoMode(buffer, len); } s32 __Loader_ReadDol(dolentry *p_entry) { static dolheader dol ATTRIBUTE_ALIGN(32); u32 cnt; s32 cfd = -1, ret; /* Open DOL file */ cfd = ES_OpenContent(DOL_INDEX); if (cfd < 0) return cfd; /* Read DOL header */ ret = ES_ReadContent(cfd, (u8 *)&dol, sizeof(dol)); if (ret < 0) goto out; /* Clear BSS */ memset(dol.bssmem, 0, dol.bsssize); /* Read TEXT section */ for (cnt = 0; cnt < 7; cnt++) { u32 offset = dol.textoff[cnt]; if (offset >= sizeof(dol)) { u8 *buffer = (u8 *)dol.textmem[cnt]; u32 len = dol.textsize[cnt]; /* Seek */ ES_SeekContent(cfd, offset, 0); /* Read */ ret = ES_ReadContent(cfd, buffer, len); if (ret < 0) goto out; /* Patch */ __Loader_PatchDol(buffer, len); } } /* Read DATA section */ for (cnt = 0; cnt < 11; cnt++) { u32 offset = dol.dataoff[cnt]; if (offset >= sizeof(dol)) { u8 *buffer = (u8 *)dol.datamem[cnt]; u32 len = dol.datasize[cnt]; /* Seek */ ES_SeekContent(cfd, offset, 0); /* Read */ ret = ES_ReadContent(cfd, buffer, len); if (ret < 0) goto out; /* Patch */ __Loader_PatchDol(buffer, len); } } /* Set entry point */ *p_entry = (dolentry)dol.entry; out: /* Close DOL file */ if (cfd >= 0) ES_CloseContent(cfd); return ret; } void __Loader_Shutdown(void) { /* Deinitialize ISFS */ ISFS_Deinitialize(); /* Shutdown IOS subsystems */ SYS_ResetSystem(SYS_SHUTDOWN, 0, 0); } s32 Loader_Execute(void) { dolentry p_entry = NULL; u64 tid; s32 ret; /* Get title ID */ ret = ES_GetTitleID(&tid); if (ret < 0) return ret; /* Load DOL */ ret = __Loader_ReadDol(&p_entry); if (ret < 0) return ret; /* Set low memory */ __Loader_SetLowMem(); /* Set video mode */ __Loader_SetVMode(tid); /* Shutdown subsystems */ __Loader_Shutdown(); /* Clear screen */ Video_Clear(COLOR_BLACK); /* Jump to the entry point */ p_entry(); return 0; }