Compare commits

...

17 Commits

Author SHA1 Message Date
Aurora Wright
725a825762 Update FatFs 2017-04-28 23:38:15 +02:00
Aurora Wright
b81f59d5ae Rewrite the LayeredFS pattern searching, small cleanup 2017-04-28 23:09:33 +02:00
Aurora Wright
39c2b8927b Fix mistake 2017-04-28 19:16:57 +02:00
Aurora Wright
89dfdac7bf This always fails 2017-04-28 12:43:56 +02:00
Aurora Wright
c087edf2ba Minor cleanup 2017-04-28 12:40:07 +02:00
Aurora Wright
db33c315f2 Instead of filtering mountpoints in the LayeredFS payload by their first letters, change known mountpoints not starting with "r" to start with "r" throughout the code 2017-04-28 00:33:30 +02:00
Aurora Wright
c7e7dd8248 Minor stuff 2017-04-27 22:32:46 +02:00
Aurora Wright
b10d82a883 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-04-27 22:17:43 +02:00
Aurora Wright
e151b3d4ef Add displaying title IDs for ARM11 exceptions 2017-04-27 22:17:19 +02:00
ihaveamac
5ccf4a45c1 update ISSUE_TEMPLATE 2017-04-26 17:10:59 -07:00
Aurora Wright
c5369a5cad Minor stuff 2017-04-26 18:04:02 +02:00
Aurora Wright
b5eba765a5 Fix update RomFSes mounted as "ext:" (such as Taiko no Tatsujin: Don Don! Mystery Adventure) 2017-04-26 17:26:39 +02:00
Aurora Wright
a5ddc38477 Minor stuff 2017-04-23 19:22:38 +02:00
Aurora Wright
8d102256a2 Improve fsTryOpenFile pattern (fixes Zelda Triforce Heroes) 2017-04-23 18:44:46 +02:00
Aurora Wright
2e561f7ea9 Cleanup 2017-04-23 05:40:22 +02:00
Aurora Wright
9656fe1b6f Change variable names for consistency 2017-04-23 03:13:38 +02:00
Aurora Wright
48c23f2a43 Attempt to fix NSMB2 by changing archive name 2017-04-23 03:11:02 +02:00
9 changed files with 148 additions and 142 deletions

View File

@@ -2,18 +2,12 @@
# #
# THIS IS NOT A SUPPORT FORUM! For support please go to: # THIS IS NOT A SUPPORT FORUM! For support please go to:
# Luma3DS GBATemp thread: https://gbatemp.net/threads/luma3ds-noob-proof-3ds-custom-firmware.411110/ # Luma3DS GBATemp thread: https://gbatemp.net/threads/luma3ds-noob-proof-3ds-custom-firmware.411110/
# /r/3dshacks: http://reddit.com/r/3dshacks/ # Nintendo Hacking: https://discord.gg/MjzatM8y
# Nintendo Hacking: https://discordapp.com/invite/C29hYvh
# IRC: #3dshacks@rizon
# #
# Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue. # Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue.
# #
# For those with GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: https://3ds.guide/troubleshooting # For those with GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: https://3ds.guide/troubleshooting
# #
# Please make sure to read "Enable region/language emulation and external .code" https://github.com/AuroraWright/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable region/language emulation and external .code" option(s). # Please make sure to read "Enable game patching" https://github.com/AuroraWright/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s).
# Keep in mind that Wiki page only applies to nightly builds. It will NOT WORK with 6.6 Stable Luma3DS.
# As of 0.02 (https://github.com/Possum/LumaLocaleSwitcher/releases) LumaLocaleSwitcher's path(s) are for 6.6 Stable and won't work with Luma3DS nightly builds newer or equal to https://github.com/AuroraWright/Luma3DS/commit/b5336c81cc82b6c5e8115249342beb5b065cdce9.
# Use this version for Luma3DS nightlies newer or equal to https://github.com/AuroraWright/Luma3DS/commit/b5336c81cc82b6c5e8115249342beb5b065cdce9 :
# https://puu.sh/uC5zW/5470adc347.7z (from https://github.com/Possum/LumaLocaleSwitcher/issues/9#issuecomment-285564014)
# #
--> -->

View File

@@ -2050,7 +2050,8 @@ FRESULT load_obj_dir (
dp->obj.fs = obj->fs; dp->obj.fs = obj->fs;
dp->obj.sclust = obj->c_scl; dp->obj.sclust = obj->c_scl;
dp->obj.stat = (BYTE)obj->c_size; dp->obj.stat = (BYTE)obj->c_size;
dp->obj.objsize = obj->c_size & 0xFFFFFF00; dp->obj.objsize = obj->c_size & 0xFFFFFF00;
dp->obj.n_frag = 0;
dp->blk_ofs = obj->c_ofs; dp->blk_ofs = obj->c_ofs;
res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */
@@ -2326,19 +2327,22 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S
if (res != FR_OK) return res; if (res != FR_OK) return res;
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */
if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */ if (dp->obj.stat & 4) { /* Has the directory been stretched? */
dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ dp->obj.stat &= ~4;
res = fill_first_frag(&dp->obj); /* Fill first fragment on the FAT if needed */ res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */
if (res != FR_OK) return res;
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */
if (res != FR_OK) return res;
res = load_obj_dir(&dj, &dp->obj); /* Load the object status */
if (res != FR_OK) return res;
st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */
st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize);
fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1;
res = store_xdir(&dj); /* Store the object status */
if (res != FR_OK) return res; if (res != FR_OK) return res;
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */
if (res != FR_OK) return res;
if (dp->obj.sclust != 0) { /* Is it a sub directory? */
res = load_obj_dir(&dj, &dp->obj); /* Load the object status */
if (res != FR_OK) return res;
dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */
st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */
st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize);
fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1;
res = store_xdir(&dj); /* Store the object status */
if (res != FR_OK) return res;
}
} }
create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */

View File

@@ -14,8 +14,8 @@
_start: _start:
; Jumps here before the fsOpenFileDirectly call ; Jumps here before the fsOpenFileDirectly call
_mountSd: _mountArchive:
b mountSd b mountArchive
.word 0xdead0000 ; Substituted opcode .word 0xdead0000 ; Substituted opcode
.word 0xdead0001 ; Branch to hooked function .word 0xdead0001 ; Branch to hooked function
@@ -25,42 +25,41 @@ _start:
.word 0xdead0002 ; Substituted opcode .word 0xdead0002 ; Substituted opcode
.word 0xdead0003 ; Branch to hooked function .word 0xdead0003 ; Branch to hooked function
; Mounts SDMC and registers the archive as 'sdmc:' ; Mounts the archive and registers it as 'lf:'
mountSd: mountArchive:
cmp r3, #3 cmp r3, #3
bne _mountSd+4 bne _mountArchive + 4
stmfd sp!, {r0-r4, lr} stmfd sp!, {r0-r4, lr}
sub sp, sp, #4 sub sp, sp, #4
load r1, archive load r1, archiveId
mov r0, sp mov r0, sp
load r4, fsMountArchive load r4, fsMountArchive
blx r4 blx r4
mov r3, #0 mov r3, #0
mov r2, #0 mov r2, #0
ldr r1, [sp] ldr r1, [sp]
addr r0, sdmcArchiveName addr r0, archiveName
load r4, fsRegisterArchive load r4, fsRegisterArchive
blx r4 blx r4
add sp, sp, #4 add sp, sp, #4
ldmfd sp!, {r0-r4, lr} ldmfd sp!, {r0-r4, lr}
b _mountSd+4 b _mountArchive + 4
; Check the path passed to iFileOpen. ; Check the path passed to iFileOpen.
; If it is trying to access a RomFS file, we try to ; If it is trying to access a RomFS file, we try to
; open it from the title folder on the sdcard. ; open it from the LayeredFS folder.
; If the file cannot be opened from the sdcard, we just open ; If the file cannot be opened, we just open
; it from its original archive like nothing happened ; it from its original archive like nothing happened
fsRedir: fsRedir:
stmfd sp!, {r0-r12, lr} stmfd sp!, {r0-r12, lr}
ldrb r12, [r1] ldrb r12, [r1]
cmp r12, #0x72 ; 'r', should include "rom:" and "rom2:" cmp r12, #0x72 ; 'r', should include "rom:", "rom2:" and "rex:"
cmpne r12, #0x70 ; 'p', should include "patch:"
bne endRedir bne endRedir
sub sp, sp, #0x400 sub sp, sp, #0x400
pathRedir: pathRedir:
stmfd sp!, {r0-r3} stmfd sp!, {r0-r3}
add r0, sp, #0x10 add r0, sp, #0x10
addr r3, sdmcCustomPath addr r3, customPath
pathRedir_1: pathRedir_1:
ldrb r2, [r3], #1 ldrb r2, [r3], #1
strh r2, [r0], #2 strh r2, [r0], #2
@@ -69,7 +68,7 @@ _start:
sub r0, r0, #2 sub r0, r0, #2
pathRedir_2: pathRedir_2:
ldrh r2, [r1], #2 ldrh r2, [r1], #2
cmp r2, #0x3A ; ':' cmp r2, #0x3A ; ':'
bne pathRedir_2 bne pathRedir_2
pathRedir_3: pathRedir_3:
ldrh r2, [r1], #2 ldrh r2, [r1], #2
@@ -78,7 +77,7 @@ _start:
bne pathRedir_3 bne pathRedir_3
ldmfd sp!, {r0-r3} ldmfd sp!, {r0-r3}
mov r1, sp mov r1, sp
bl _fsRedir+4 bl _fsRedir + 4
add sp, sp, #0x400 add sp, sp, #0x400
cmp r0, #0 cmp r0, #0
@@ -86,16 +85,14 @@ _start:
ldmfd sp!, {r0-r12, lr} ldmfd sp!, {r0-r12, lr}
moveq r0, #0 moveq r0, #0
bxeq lr bxeq lr
b _fsRedir+4 b _fsRedir + 4
.pool .pool
.align 4 .align 4
sdmcArchiveName : .word 0xdead0007 archiveName : .dcb "lf:", 0
.dcb ":", 0 fsMountArchive : .word 0xdead0005
.align 4 fsRegisterArchive : .word 0xdead0006
fsMountArchive : .word 0xdead0005 archiveId : .word 0xdead0007
fsRegisterArchive : .word 0xdead0006 customPath : .word 0xdead0004
archive : .word 0xdead0008
sdmcCustomPath : .word 0xdead0004
.close .close

View File

@@ -163,19 +163,4 @@ Result FSLDR_OpenDirectory(Handle* out, FS_Archive archive, FS_Path path)
if(out) *out = cmdbuf[3]; if(out) *out = cmdbuf[3];
return cmdbuf[1]; return cmdbuf[1];
}
Result FSDIRLDR_Close(Handle handle)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x802,0,0); // 0x8020000
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
ret = cmdbuf[1];
if(R_SUCCEEDED(ret)) ret = svcCloseHandle(handle);
return ret;
} }

View File

@@ -9,5 +9,4 @@ Result FSLDR_SetPriority(u32 priority);
Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes); Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes);
Result FSLDR_OpenArchive(FS_Archive* archive, FS_ArchiveID id, FS_Path path); Result FSLDR_OpenArchive(FS_Archive* archive, FS_ArchiveID id, FS_Path path);
Result FSLDR_CloseArchive(FS_Archive archive); Result FSLDR_CloseArchive(FS_Archive archive);
Result FSLDR_OpenDirectory(Handle* out, FS_Archive archive, FS_Path path); Result FSLDR_OpenDirectory(Handle* out, FS_Archive archive, FS_Path path);
Result FSDIRLDR_Close(Handle handle);

View File

@@ -13,7 +13,7 @@ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, in
{ {
u32 i; u32 i;
for(i = 0; i < count; i++) for(i = 0; !count || i < count; i++)
{ {
u8 *found = memsearch(start, pattern, size, patSize); u8 *found = memsearch(start, pattern, size, patSize);
@@ -52,7 +52,7 @@ static u32 dirCheck(FS_ArchiveID archiveId, const char *path)
else else
{ {
ret = R_SUCCEEDED(FSLDR_OpenDirectory(&handle, archive, dirPath)) ? 0 : 2; ret = R_SUCCEEDED(FSLDR_OpenDirectory(&handle, archive, dirPath)) ? 0 : 2;
if(ret) FSDIRLDR_Close(handle); if(!ret) FSDIR_Close(handle);
FSLDR_CloseArchive(archive); FSLDR_CloseArchive(archive);
} }
@@ -87,8 +87,7 @@ static inline void loadCFWInfo(void)
svcGetCFWInfo(&info); svcGetCFWInfo(&info);
IFile file; IFile file;
if(LOADERFLAG(ISSAFEMODE) && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted if(LOADERFLAG(ISSAFEMODE)) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted
IFile_Close(&file);
infoLoaded = true; infoLoaded = true;
} }
@@ -187,17 +186,16 @@ static inline u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos <= code + size - 12; CFGU_GetConfigInfoBlk2_endPos += 4) for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos <= code + size - 12; CFGU_GetConfigInfoBlk2_endPos += 4)
{ {
static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082};
//There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want //There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want
u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos; u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos;
if(cmp[0] != CFGU_GetConfigInfoBlk2_endPattern[0] || cmp[1] != CFGU_GetConfigInfoBlk2_endPattern[1]) continue; if(cmp[0] != 0xE8BD8010 || cmp[1] != 0x00010082) continue;
for(u32 i = 0; i < n; i++) for(u32 i = 0; i < n; i++)
if(possible[i] == cmp[2]) if(possible[i] == cmp[2])
{ {
*CFGUHandleOffset = cmp[2]; *CFGUHandleOffset = cmp[2];
return CFGU_GetConfigInfoBlk2_endPos; return CFGU_GetConfigInfoBlk2_endPos;
} }
@@ -257,14 +255,12 @@ static inline void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHa
{ {
for(u8 *cmdPos = code; cmdPos <= code + size - 28; cmdPos += 4) for(u8 *cmdPos = code; cmdPos <= code + size - 28; cmdPos += 4)
{ {
static const u32 cfgSecureInfoGetRegionCmdPattern[] = {0xEE1D0F70, 0xE3A00802};
u32 *cmp = (u32 *)cmdPos; u32 *cmp = (u32 *)cmdPos;
if(*cmp != cfgSecureInfoGetRegionCmdPattern[1]) continue; if(*cmp != 0xE3A00802) continue;
for(u32 i = 1; i < 3; i++) for(u32 i = 1; i < 3; i++)
if((*(cmp - i) & 0xFFFF0FFF) == cfgSecureInfoGetRegionCmdPattern[0] && *((u16 *)cmdPos + 5) == 0xE59F && if((*(cmp - i) & 0xFFFF0FFF) == 0xEE1D0F70 && *((u16 *)cmdPos + 5) == 0xE59F &&
*(u32 *)(cmdPos + 16 + *((u16 *)cmdPos + 4)) == CFGUHandleOffset) *(u32 *)(cmdPos + 16 + *((u16 *)cmdPos + 4)) == CFGUHandleOffset)
{ {
cmp[3] = 0xE3A00000 | regionId; //mov r0, =regionId cmp[3] = 0xE3A00000 | regionId; //mov r0, =regionId
@@ -278,7 +274,7 @@ static inline void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHa
} }
} }
static u32 findFunctionStart(u8* code, u32 pos) static u32 findFunctionStart(u8 *code, u32 pos)
{ {
while(pos >= 4) while(pos >= 4)
{ {
@@ -289,47 +285,56 @@ static u32 findFunctionStart(u8* code, u32 pos)
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }
static inline bool findLayeredFsSymbols(u8* code, u32 size, u32 *fsMountArchive, u32 *fsRegisterArchive, u32 *fsTryOpenFile, u32 *fsOpenFileDirectly) static inline bool findLayeredFsSymbols(u8 *code, u32 size, u32 *fsMountArchive, u32 *fsRegisterArchive, u32 *fsTryOpenFile, u32 *fsOpenFileDirectly)
{ {
u32 found = 0,
*temp = NULL;
for(u32 addr = 0; addr <= size - 4; addr += 4) for(u32 addr = 0; addr <= size - 4; addr += 4)
{ {
if(*fsMountArchive == 0xFFFFFFFF) switch(*(u32 *)(code + addr))
{ {
if(addr <= size - 12 && *(u32 *)(code + addr) == 0xE5970010) case 0xE5970010:
{ if(addr <= size - 12 && *fsMountArchive == 0xFFFFFFFF && *(u32 *)(code + addr + 4) == 0xE1CD20D8 && (*(u32 *)(code + addr + 8) & 0xFFFFFF) == 0x008D0000) temp = fsMountArchive;
if((*(u32 *)(code + addr + 4) == 0xE1CD20D8) && ((*(u32 *)(code + addr + 8) & 0xFFFFFF) == 0x008D0000)) break;
*fsMountArchive = findFunctionStart(code, addr); case 0xE24DD028:
} if(addr <= size - 16 && *fsMountArchive == 0xFFFFFFFF && *(u32 *)(code + addr + 4) == 0xE1A04000 && *(u32 *)(code + addr + 8) == 0xE59F60A8 && *(u32 *)(code + addr + 0xC) == 0xE3A0C001) temp = fsMountArchive;
else if(addr <= size - 16 && *(u32 *)(code + addr) == 0xE24DD028) break;
{ case 0xE3500008:
if((*(u32 *)(code + addr + 4) == 0xE1A04000) && (*(u32 *)(code + addr + 8) == 0xE59F60A8) && (*(u32 *)(code + addr + 0xC) == 0xE3A0C001)) if(addr <= size - 12 && *fsRegisterArchive == 0xFFFFFFFF && (*(u32 *)(code + addr + 4) & 0xFFF00FF0) == 0xE1800400 && (*(u32 *)(code + addr + 8) & 0xFFF00FF0) == 0xE1800FC0) temp = fsRegisterArchive;
*fsMountArchive = findFunctionStart(code, addr); break;
} case 0xE351003A:
if(addr <= size - 0x40 && *fsTryOpenFile == 0xFFFFFFFF && *(u32 *)(code + addr + 4) == 0x1AFFFFFC && *(u32 *)(code + addr + 0x34) == 0xE590C000 && *(u32 *)(code + addr + 0x3C) == 0xE12FFF3C) temp = fsTryOpenFile;
break;
case 0x08030204:
if(*fsOpenFileDirectly == 0xFFFFFFFF) temp = fsOpenFileDirectly;
break;
} }
if(addr <= size - 12 && *fsRegisterArchive == 0xFFFFFFFF && *(u32 *)(code + addr) == 0xE3500008 && (*(u32 *)(code + addr + 4) & 0xFFF00FF0) == 0xE1800400 && (*(u32 *)(code + addr + 8) & 0xFFF00FF0) == 0xE1800FC0) if(temp != NULL)
*fsRegisterArchive = findFunctionStart(code, addr); {
*temp = findFunctionStart(code, addr);
if(addr <= size - 16 && *fsTryOpenFile == 0xFFFFFFFF && *(u32 *)(code + addr + 0xC) == 0xE12FFF3C && if(*temp != 0xFFFFFFFF)
((*(u32 *)(code + addr) == 0xE1A0100D) || (*(u32 *)(code + addr) == 0xE28D1010)) && (*(u32 *)(code + addr + 4) == 0xE590C000) && {
((*(u32 *)(code + addr + 8) == 0xE1A00004) || (*(u32 *)(code + addr + 8) == 0xE1A00005))) found++;
*fsTryOpenFile = findFunctionStart(code, addr); if(found == 4) break;
}
if(*fsOpenFileDirectly == 0xFFFFFFFF && *(u32 *)(code + addr) == 0x08030204) temp = NULL;
*fsOpenFileDirectly = findFunctionStart(code, addr); }
if(*fsMountArchive != 0xFFFFFFFF && *fsRegisterArchive != 0xFFFFFFFF && *fsTryOpenFile != 0xFFFFFFFF && *fsOpenFileDirectly != 0xFFFFFFFF) return true;
} }
return false; return found == 4;
} }
static inline bool findLayeredFsPayloadOffset(u8* code, u32 size, u32 *payloadOffset) static inline bool findLayeredFsPayloadOffset(u8 *code, u32 size, u32 *payloadOffset)
{ {
//First check for sufficient padding at the end of the .text segment //First check for sufficient padding at the end of the .text segment
if(((size + 4095) & 0xfffff000) - size >= romfsredir_bin_size) if(((size + 4095) & 0xFFFFF000) - size >= romfsredir_bin_size)
{ {
*payloadOffset = size; *payloadOffset = size;
return true; return true;
} }
@@ -359,6 +364,7 @@ static inline bool findLayeredFsPayloadOffset(u8* code, u32 size, u32 *payloadOf
if(func != 0xFFFFFFFF) if(func != 0xFFFFFFFF)
{ {
*payloadOffset = func; *payloadOffset = func;
return true; return true;
} }
} }
@@ -475,13 +481,13 @@ static inline bool loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageI
if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) goto exit; if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) goto exit;
u32 i, static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"},
j; *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
for(i = 0; i < 7; i++) u32 i;
for(i = 0; i < sizeof(regions) / sizeof(char *); i++)
{ {
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
if(memcmp(buf, regions[i], 3) == 0) if(memcmp(buf, regions[i], 3) == 0)
{ {
*regionId = (u8)i; *regionId = (u8)i;
@@ -489,26 +495,26 @@ static inline bool loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageI
} }
} }
for(j = 0; j < 12; j++) if(i != sizeof(regions) / sizeof(char *))
{ {
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"}; for(i = 0; i < sizeof(languages) / sizeof(char *); i++)
if(memcmp(buf + 4, languages[j], 2) == 0)
{ {
*languageId = (u8)j; if(memcmp(buf + 4, languages[i], 2) == 0)
break; {
*languageId = (u8)i;
ret = true;
break;
}
} }
} }
ret = i != 7 && j != 12;
exit: exit:
IFile_Close(&file); IFile_Close(&file);
return ret; return ret;
} }
static inline bool patchLayeredFs(u64 progId, u8* code, u32 size) static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize)
{ {
/* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/romfs" /* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/romfs"
If it exists it should be a folder containing ROMFS files */ If it exists it should be a folder containing ROMFS files */
@@ -516,11 +522,9 @@ static inline bool patchLayeredFs(u64 progId, u8* code, u32 size)
char path[] = "/luma/titles/0000000000000000/romfs"; char path[] = "/luma/titles/0000000000000000/romfs";
progIdToStr(path + 28, progId); progIdToStr(path + 28, progId);
u32 archive = checkLumaDir(path); u32 archiveId = checkLumaDir(path);
if(!archive) return true; if(!archiveId) return true;
const char *mount = archive == ARCHIVE_SDMC ? "sdmc:" : "nand:";
u32 fsMountArchive = 0xFFFFFFFF, u32 fsMountArchive = 0xFFFFFFFF,
fsRegisterArchive = 0xFFFFFFFF, fsRegisterArchive = 0xFFFFFFFF,
@@ -528,8 +532,23 @@ static inline bool patchLayeredFs(u64 progId, u8* code, u32 size)
fsOpenFileDirectly = 0xFFFFFFFF, fsOpenFileDirectly = 0xFFFFFFFF,
payloadOffset; payloadOffset;
if(!findLayeredFsSymbols(code, size, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly) || if(!findLayeredFsSymbols(code, textSize, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly) ||
!findLayeredFsPayloadOffset(code, size, &payloadOffset)) return false; !findLayeredFsPayloadOffset(code, textSize, &payloadOffset)) return false;
static const char *updateRomFsMounts[] = { "patch:",
"ext:" },
patch = 'r';
//Change update RomFS mountpoints to start with "r"
for(u32 i = 0, ret = 0; i < sizeof(updateRomFsMounts) / sizeof(char *) && !ret; i++)
{
ret = patchMemory(code, size,
updateRomFsMounts[i],
strnlen(updateRomFsMounts[i], 255), 0,
&patch,
sizeof(patch), 0
);
}
//Setup the payload //Setup the payload
u8 *payload = code + payloadOffset; u8 *payload = code + payloadOffset;
@@ -539,7 +558,7 @@ static inline bool patchLayeredFs(u64 progId, u8* code, u32 size)
u32 *payload32 = (u32 *)payload; u32 *payload32 = (u32 *)payload;
for(u32 i = 0; i < romfsredir_bin_size / 4; i++) for(u32 i = 0; i < romfsredir_bin_size / 4; i++)
{ {
switch (payload32[i]) switch(payload32[i])
{ {
case 0xdead0000: case 0xdead0000:
payload32[i] = *(u32 *)(code + fsOpenFileDirectly); payload32[i] = *(u32 *)(code + fsOpenFileDirectly);
@@ -554,8 +573,8 @@ static inline bool patchLayeredFs(u64 progId, u8* code, u32 size)
payload32[i] = MAKE_BRANCH(payloadOffset + i * 4, fsTryOpenFile + 4); payload32[i] = MAKE_BRANCH(payloadOffset + i * 4, fsTryOpenFile + 4);
break; break;
case 0xdead0004: case 0xdead0004:
memcpy(payload32 + i, mount, 5); memcpy(payload32 + i, "lf:", 3);
memcpy((u8 *)(payload32 + i) + 5, path, sizeof(path)); memcpy((u8 *)(payload32 + i) + 3, path, sizeof(path));
break; break;
case 0xdead0005: case 0xdead0005:
payload32[i] = 0x100000 + fsMountArchive; payload32[i] = 0x100000 + fsMountArchive;
@@ -564,10 +583,7 @@ static inline bool patchLayeredFs(u64 progId, u8* code, u32 size)
payload32[i] = 0x100000 + fsRegisterArchive; payload32[i] = 0x100000 + fsRegisterArchive;
break; break;
case 0xdead0007: case 0xdead0007:
memcpy(payload32 + i, mount, 4); payload32[i] = archiveId;
break;
case 0xdead0008:
payload32[i] = archive;
break; break;
} }
} }
@@ -841,7 +857,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
if(!loadTitleCodeSection(progId, code, size) || if(!loadTitleCodeSection(progId, code, size) ||
!applyCodeIpsPatch(progId, code, size) || !applyCodeIpsPatch(progId, code, size) ||
!loadTitleLocaleConfig(progId, &regionId, &languageId) || !loadTitleLocaleConfig(progId, &regionId, &languageId) ||
!patchLayeredFs(progId, code, textSize)) goto error; !patchLayeredFs(progId, code, size, textSize)) goto error;
if(regionId != 0xFF) if(regionId != 0xFF)
{ {

View File

@@ -155,8 +155,14 @@ void detectAndProcessExceptionDumps(void)
if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0) if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0)
{ {
char processName[] = "Current process: "; char processName[45] = "Current process: ";
memcpy(processName + sizeof(processName) - 9, (void *)additionalData, 8); memcpy(processName + 17, (void *)additionalData, 8);
hexItoa(*(vu32 *)(additionalData + 12), hexString, 8, true);
concatenateStrings(processName, " (");
concatenateStrings(processName, hexString);
hexItoa(*(vu32 *)(additionalData + 8), hexString, 8, true);
concatenateStrings(processName, hexString);
concatenateStrings(processName, ")");
posY = drawString(processName, true, 10, posY + SPACING_Y, COLOR_WHITE); posY = drawString(processName, true, 10, posY + SPACING_Y, COLOR_WHITE);
} }

View File

@@ -2050,7 +2050,8 @@ FRESULT load_obj_dir (
dp->obj.fs = obj->fs; dp->obj.fs = obj->fs;
dp->obj.sclust = obj->c_scl; dp->obj.sclust = obj->c_scl;
dp->obj.stat = (BYTE)obj->c_size; dp->obj.stat = (BYTE)obj->c_size;
dp->obj.objsize = obj->c_size & 0xFFFFFF00; dp->obj.objsize = obj->c_size & 0xFFFFFF00;
dp->obj.n_frag = 0;
dp->blk_ofs = obj->c_ofs; dp->blk_ofs = obj->c_ofs;
res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */
@@ -2326,19 +2327,22 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S
if (res != FR_OK) return res; if (res != FR_OK) return res;
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */
if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */ if (dp->obj.stat & 4) { /* Has the directory been stretched? */
dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ dp->obj.stat &= ~4;
res = fill_first_frag(&dp->obj); /* Fill first fragment on the FAT if needed */ res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */
if (res != FR_OK) return res;
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */
if (res != FR_OK) return res;
res = load_obj_dir(&dj, &dp->obj); /* Load the object status */
if (res != FR_OK) return res;
st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */
st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize);
fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1;
res = store_xdir(&dj); /* Store the object status */
if (res != FR_OK) return res; if (res != FR_OK) return res;
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */
if (res != FR_OK) return res;
if (dp->obj.sclust != 0) { /* Is it a sub directory? */
res = load_obj_dir(&dj, &dp->obj); /* Load the object status */
if (res != FR_OK) return res;
dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */
st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */
st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize);
fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1;
res = store_xdir(&dj); /* Store the object status */
if (res != FR_OK) return res;
}
} }
create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */

View File

@@ -240,7 +240,8 @@ boot:
bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES); bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES);
u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, isSafeMode); u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, isSafeMode);
bool doUnitinfoPatch = CONFIG(PATCHUNITINFO), enableExceptionHandlers = CONFIG(ENABLEEXCEPTIONHANDLERS); bool doUnitinfoPatch = CONFIG(PATCHUNITINFO),
enableExceptionHandlers = CONFIG(ENABLEEXCEPTIONHANDLERS);
u32 res; u32 res;
switch(firmType) switch(firmType)
{ {