2015-08-04 21:57:37 -04:00
|
|
|
/*
|
2016-07-05 16:05:53 +02:00
|
|
|
* This file is part of Luma3DS
|
2022-03-13 18:00:00 +00:00
|
|
|
* Copyright (C) 2016-2021 Aurora Wright, TuxSH
|
2016-07-05 16:05:53 +02:00
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*
|
2017-06-05 02:02:04 +02:00
|
|
|
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
|
|
|
|
* * Requiring preservation of specified reasonable legal notices or
|
|
|
|
|
* author attributions in that material or in the Appropriate Legal
|
|
|
|
|
* Notices displayed by works containing it.
|
|
|
|
|
* * Prohibiting misrepresentation of the origin of that material,
|
|
|
|
|
* or requiring that modified versions of such material be marked in
|
|
|
|
|
* reasonable ways as different from the original version.
|
2015-08-04 21:57:37 -04:00
|
|
|
*/
|
|
|
|
|
|
2016-11-01 19:05:04 +01:00
|
|
|
/*
|
|
|
|
|
* Code for locating the SDMMC struct by Normmatt
|
|
|
|
|
*/
|
|
|
|
|
|
2017-08-28 14:46:18 +02:00
|
|
|
|
2015-08-04 21:57:37 -04:00
|
|
|
#include "emunand.h"
|
2016-01-23 03:53:45 -05:00
|
|
|
#include "memory.h"
|
2017-08-28 02:40:05 +02:00
|
|
|
#include "utils.h"
|
2015-08-04 21:57:37 -04:00
|
|
|
#include "fatfs/sdmmc/sdmmc.h"
|
2018-05-22 22:55:04 +02:00
|
|
|
#include "large_patches.h"
|
2015-08-04 21:57:37 -04:00
|
|
|
|
2017-05-26 03:07:39 +02:00
|
|
|
u32 emuOffset,
|
2017-08-28 14:46:18 +02:00
|
|
|
emuHeader;
|
2016-10-10 01:34:53 +02:00
|
|
|
|
2023-07-09 00:22:45 +02:00
|
|
|
void locateEmuNand(FirmwareSource *nandType, u32 *emunandIndex, bool configureCtrNandParams)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-09-22 20:00:48 +02:00
|
|
|
static u8 __attribute__((aligned(4))) temp[0x200];
|
|
|
|
|
static u32 nandSize = 0,
|
|
|
|
|
fatStart;
|
2016-09-07 18:04:31 +02:00
|
|
|
|
2016-09-22 22:19:27 +02:00
|
|
|
if(!nandSize)
|
2016-09-22 20:00:48 +02:00
|
|
|
{
|
|
|
|
|
nandSize = getMMCDevice(0)->total_size;
|
2016-09-22 22:19:27 +02:00
|
|
|
sdmmc_sdcard_readsectors(0, 1, temp);
|
2016-09-22 20:00:48 +02:00
|
|
|
fatStart = *(u32 *)(temp + 0x1C6); //First sector of the FAT partition
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 00:22:45 +02:00
|
|
|
/*if (*nandType == FIRMWARE_SYSNAND)
|
|
|
|
|
return;*/
|
|
|
|
|
|
|
|
|
|
for(u32 i = 0; i < 3; i++) // Test the different kinds of multi-EmuNAND there are, unless we are looking for the first one
|
2016-09-07 18:04:31 +02:00
|
|
|
{
|
2016-09-22 20:00:48 +02:00
|
|
|
static const u32 roundedMinsizes[] = {0x1D8000, 0x26E000};
|
|
|
|
|
|
2016-09-07 18:04:31 +02:00
|
|
|
u32 nandOffset;
|
|
|
|
|
switch(i)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
2016-09-07 22:22:31 +02:00
|
|
|
nandOffset = ROUND_TO_4MB(nandSize + 1); //"Default" layout
|
2016-09-07 18:04:31 +02:00
|
|
|
break;
|
|
|
|
|
case 2:
|
2016-10-10 01:34:53 +02:00
|
|
|
nandOffset = roundedMinsizes[ISN3DS ? 1 : 0]; //"Minsize" layout
|
2016-09-07 18:04:31 +02:00
|
|
|
break;
|
2016-11-26 22:46:46 +01:00
|
|
|
case 0:
|
2023-07-09 00:22:45 +02:00
|
|
|
nandOffset = nandSize > 0x200000 ? 0x400000 : 0x200000; //"Legacy" layout
|
2016-09-07 18:04:31 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-09 00:22:45 +02:00
|
|
|
nandOffset *= *emunandIndex; // always 0 for 1st EmuNAND
|
2016-09-08 00:49:55 +02:00
|
|
|
|
2016-10-10 01:34:53 +02:00
|
|
|
if(fatStart >= nandOffset + roundedMinsizes[ISN3DS ? 1 : 0])
|
2016-09-07 18:04:31 +02:00
|
|
|
{
|
2016-09-22 20:00:48 +02:00
|
|
|
//Check for RedNAND
|
2016-10-10 01:34:53 +02:00
|
|
|
if(!sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) && memcmp(temp + 0x100, "NCSD", 4) == 0)
|
2016-09-22 20:00:48 +02:00
|
|
|
{
|
2023-07-09 00:22:45 +02:00
|
|
|
if (configureCtrNandParams)
|
|
|
|
|
{
|
|
|
|
|
emuOffset = nandOffset + 1;
|
|
|
|
|
emuHeader = 0;
|
|
|
|
|
}
|
2017-08-28 14:46:18 +02:00
|
|
|
return;
|
2016-09-22 20:00:48 +02:00
|
|
|
}
|
2016-09-07 18:04:31 +02:00
|
|
|
|
2016-09-22 20:00:48 +02:00
|
|
|
//Check for Gateway EmuNAND
|
2016-10-10 01:34:53 +02:00
|
|
|
else if(i != 2 && !sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) && memcmp(temp + 0x100, "NCSD", 4) == 0)
|
2016-09-22 20:00:48 +02:00
|
|
|
{
|
2023-07-09 00:22:45 +02:00
|
|
|
if (configureCtrNandParams)
|
|
|
|
|
{
|
|
|
|
|
emuOffset = nandOffset;
|
|
|
|
|
emuHeader = nandSize;
|
|
|
|
|
}
|
2016-11-15 19:29:48 +01:00
|
|
|
return;
|
2016-09-22 20:00:48 +02:00
|
|
|
}
|
2016-09-07 18:04:31 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-09 00:22:45 +02:00
|
|
|
if(*emunandIndex == 0) break; // See above comments
|
2016-09-07 18:04:31 +02:00
|
|
|
}
|
|
|
|
|
|
2016-09-08 02:12:29 +02:00
|
|
|
//Fallback to the first EmuNAND if there's no second/third/fourth one, or to SysNAND if there isn't any
|
2023-07-09 00:22:45 +02:00
|
|
|
if(*emunandIndex != 0)
|
2016-09-07 18:04:31 +02:00
|
|
|
{
|
2023-07-09 00:22:45 +02:00
|
|
|
*emunandIndex = 0;
|
|
|
|
|
locateEmuNand(nandType, emunandIndex, configureCtrNandParams);
|
2016-09-07 18:04:31 +02:00
|
|
|
}
|
2016-11-15 19:29:48 +01:00
|
|
|
else *nandType = FIRMWARE_SYSNAND;
|
2016-01-23 03:53:45 -05:00
|
|
|
}
|
|
|
|
|
|
2017-06-19 18:13:59 +02:00
|
|
|
static inline u32 getOldSdmmc(u32 *sdmmc, u32 firmVersion)
|
|
|
|
|
{
|
|
|
|
|
switch(firmVersion)
|
|
|
|
|
{
|
|
|
|
|
case 0x18:
|
|
|
|
|
*sdmmc = 0x080D91D8;
|
|
|
|
|
break;
|
|
|
|
|
case 0x1D:
|
|
|
|
|
case 0x1F:
|
|
|
|
|
*sdmmc = 0x080D8CD0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-10 01:34:53 +02:00
|
|
|
static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-01-23 03:53:45 -05:00
|
|
|
//Look for struct code
|
2017-06-09 14:26:51 +02:00
|
|
|
static const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
2016-10-10 01:34:53 +02:00
|
|
|
|
2016-09-03 15:35:46 +02:00
|
|
|
const u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
2016-03-21 18:56:41 +01:00
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
if(off == NULL) return 1;
|
2016-10-10 23:46:25 +02:00
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
*sdmmc = *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
|
2016-10-10 01:34:53 +02:00
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
return 0;
|
2016-01-23 03:53:45 -05:00
|
|
|
}
|
|
|
|
|
|
2023-08-12 18:00:08 +02:00
|
|
|
static inline u32 patchNandRw(u8 *pos, u32 size, u32 hookAddr)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-01-23 03:53:45 -05:00
|
|
|
//Look for read/write code
|
2017-06-09 14:26:51 +02:00
|
|
|
static const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
2016-10-10 01:34:53 +02:00
|
|
|
|
|
|
|
|
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
|
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
if(readOffset == NULL) return 1;
|
2016-10-10 01:34:53 +02:00
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
readOffset -= 3;
|
2016-02-08 03:37:03 +01:00
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern));
|
2016-10-10 23:46:25 +02:00
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
if(writeOffset == NULL) return 1;
|
2016-05-25 15:26:51 +02:00
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
writeOffset -= 3;
|
|
|
|
|
*readOffset = *writeOffset = 0x4C00;
|
|
|
|
|
readOffset[1] = writeOffset[1] = 0x47A0;
|
2023-08-12 18:00:08 +02:00
|
|
|
((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = hookAddr;
|
2016-10-10 01:34:53 +02:00
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
return 0;
|
2016-05-25 14:34:43 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-12 18:00:08 +02:00
|
|
|
u32 patchEmuNand(u8 *process9Offset, u32 process9Size, u32 firmVersion)
|
2016-05-25 14:34:43 +02:00
|
|
|
{
|
2016-10-10 01:34:53 +02:00
|
|
|
u32 ret = 0;
|
|
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
//Add the data of the found EmuNAND
|
2018-05-22 22:55:04 +02:00
|
|
|
emunandPatchNandOffset = emuOffset;
|
|
|
|
|
emunandPatchNcsdHeaderOffset = emuHeader;
|
2016-11-15 19:29:48 +01:00
|
|
|
|
|
|
|
|
//Find and add the SDMMC struct
|
|
|
|
|
u32 sdmmc;
|
2017-06-19 18:13:59 +02:00
|
|
|
ret += !ISN3DS && firmVersion < 0x25 ? getOldSdmmc(&sdmmc, firmVersion) : getSdmmc(process9Offset, process9Size, &sdmmc);
|
2018-05-22 22:55:04 +02:00
|
|
|
if(!ret) emunandPatchSdmmcStructPtr = sdmmc;
|
|
|
|
|
|
2016-11-15 19:29:48 +01:00
|
|
|
//Add EmuNAND hooks
|
2023-08-12 18:00:08 +02:00
|
|
|
ret += patchNandRw(process9Offset, process9Size, (u32)emunandPatch);
|
2016-05-25 14:34:43 +02:00
|
|
|
|
2016-10-10 01:34:53 +02:00
|
|
|
return ret;
|
2017-06-05 02:02:04 +02:00
|
|
|
}
|