2015-08-05 03:57:37 +02:00
|
|
|
/*
|
2016-07-05 16:05:53 +02:00
|
|
|
* This file is part of Luma3DS
|
|
|
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*
|
|
|
|
* Additional Terms 7.b of GPLv3 applies 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.
|
2015-08-05 03:57:37 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "emunand.h"
|
2016-01-23 09:53:45 +01:00
|
|
|
#include "memory.h"
|
2015-08-05 03:57:37 +02:00
|
|
|
#include "fatfs/sdmmc/sdmmc.h"
|
2016-05-25 14:34:43 +02:00
|
|
|
#include "../build/emunandpatch.h"
|
2015-08-05 03:57:37 +02:00
|
|
|
|
2016-09-08 02:12:29 +02:00
|
|
|
void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-08-16 18:47:27 +02:00
|
|
|
static u8 temp[0x200];
|
2016-03-31 15:57:02 +02:00
|
|
|
const u32 nandSize = getMMCDevice(0)->total_size;
|
2016-09-07 18:04:31 +02:00
|
|
|
bool found = false;
|
|
|
|
|
2016-09-12 13:19:59 +02:00
|
|
|
for(u32 i = 0; i < 3 && !found; i++)
|
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:
|
|
|
|
nandOffset = isN3DS ? 0x26E000 : 0x1D8000; //"Minsize" layout
|
|
|
|
break;
|
|
|
|
default:
|
2016-09-08 02:12:29 +02:00
|
|
|
nandOffset = *nandType == FIRMWARE_EMUNAND ? 0 : (nandSize > 0x200000 ? 0x400000 : 0x200000); //"Legacy" layout
|
2016-09-07 18:04:31 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-09-08 02:12:29 +02:00
|
|
|
if(*nandType != FIRMWARE_EMUNAND) nandOffset *= ((u32)*nandType - 1);
|
2016-09-08 00:49:55 +02:00
|
|
|
|
2016-09-07 18:04:31 +02:00
|
|
|
//Check for RedNAND
|
|
|
|
if(!sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) && *(u32 *)(temp + 0x100) == NCSD_MAGIC)
|
|
|
|
{
|
|
|
|
emuOffset = nandOffset + 1;
|
|
|
|
*emuHeader = nandOffset + 1;
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
|
2016-09-08 02:12:29 +02:00
|
|
|
//Check for Gateway EmuNAND
|
2016-09-14 12:01:39 +02:00
|
|
|
else if(i != 2 && !sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) && *(u32 *)(temp + 0x100) == NCSD_MAGIC)
|
2016-09-07 18:04:31 +02:00
|
|
|
{
|
|
|
|
emuOffset = nandOffset;
|
|
|
|
*emuHeader = nandOffset + nandSize;
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
|
2016-09-08 02:12:29 +02:00
|
|
|
if(*nandType == FIRMWARE_EMUNAND) break;
|
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
|
2016-09-07 18:04:31 +02:00
|
|
|
if(!found)
|
|
|
|
{
|
2016-09-08 02:12:29 +02:00
|
|
|
if(*nandType != FIRMWARE_EMUNAND)
|
2016-09-07 18:04:31 +02:00
|
|
|
{
|
2016-09-08 02:12:29 +02:00
|
|
|
*nandType = FIRMWARE_EMUNAND;
|
|
|
|
locateEmuNand(emuHeader, nandType);
|
2016-09-07 18:04:31 +02:00
|
|
|
}
|
2016-09-08 02:12:29 +02:00
|
|
|
else *nandType = FIRMWARE_SYSNAND;
|
2016-09-07 18:04:31 +02:00
|
|
|
}
|
2016-01-23 09:53:45 +01:00
|
|
|
}
|
|
|
|
|
2016-09-06 15:52:08 +02:00
|
|
|
static inline u8 *getFreeK9Space(u8 *pos, u32 size)
|
2016-05-25 15:26:51 +02:00
|
|
|
{
|
|
|
|
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
|
|
|
|
|
|
|
//Looking for the last free space before Process9
|
2016-09-03 15:35:46 +02:00
|
|
|
return memsearch(pos + 0x13500, pattern, size - 0x13500, sizeof(pattern)) + 0x455;
|
2016-05-25 15:26:51 +02:00
|
|
|
}
|
|
|
|
|
2016-08-29 15:35:24 +02:00
|
|
|
static inline u32 getSdmmc(u8 *pos, u32 size)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-01-23 09:53:45 +01:00
|
|
|
//Look for struct code
|
2016-03-26 19:21:17 +01:00
|
|
|
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
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-05-05 04:43:44 +02:00
|
|
|
return *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
|
2016-01-23 09:53:45 +01:00
|
|
|
}
|
|
|
|
|
2016-08-29 15:35:24 +02:00
|
|
|
static inline void patchNandRw(u8 *pos, u32 size, u32 branchOffset)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-05-25 15:26:51 +02:00
|
|
|
const u16 nandRedir[2] = {0x4C00, 0x47A0};
|
|
|
|
|
2016-01-23 09:53:45 +01:00
|
|
|
//Look for read/write code
|
2016-03-26 19:21:17 +01:00
|
|
|
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
2016-02-08 03:37:03 +01:00
|
|
|
|
2016-09-03 15:35:46 +02:00
|
|
|
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)) - 3,
|
|
|
|
*writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern)) - 3;
|
2016-05-25 15:26:51 +02:00
|
|
|
|
|
|
|
*readOffset = nandRedir[0];
|
|
|
|
readOffset[1] = nandRedir[1];
|
|
|
|
((u32 *)readOffset)[1] = branchOffset;
|
|
|
|
*writeOffset = nandRedir[0];
|
|
|
|
writeOffset[1] = nandRedir[1];
|
|
|
|
((u32 *)writeOffset)[1] = branchOffset;
|
2016-02-08 03:37:03 +01:00
|
|
|
}
|
|
|
|
|
2016-08-29 15:35:24 +02:00
|
|
|
static inline void patchMpu(u8 *pos, u32 size)
|
2016-04-02 17:58:06 +02:00
|
|
|
{
|
2016-02-08 23:46:01 +01:00
|
|
|
//Look for MPU pattern
|
2016-03-26 19:21:17 +01:00
|
|
|
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
2016-02-08 03:37:03 +01:00
|
|
|
|
2016-09-03 15:35:46 +02:00
|
|
|
u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
|
2016-03-29 17:43:53 +02:00
|
|
|
|
2016-09-02 22:56:57 +02:00
|
|
|
off[0] = 0x00360003;
|
|
|
|
off[6] = 0x00200603;
|
|
|
|
off[9] = 0x001C0603;
|
2016-05-25 14:34:43 +02:00
|
|
|
}
|
|
|
|
|
2016-08-29 15:35:24 +02:00
|
|
|
void patchEmuNand(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuHeader, u32 branchAdditive)
|
2016-05-25 14:34:43 +02:00
|
|
|
{
|
2016-09-08 02:12:29 +02:00
|
|
|
//Copy EmuNAND code
|
2016-09-06 15:52:08 +02:00
|
|
|
u8 *freeK9Space = getFreeK9Space(arm9Section, arm9SectionSize);
|
2016-08-29 15:35:24 +02:00
|
|
|
memcpy(freeK9Space, emunand, emunand_size);
|
2016-05-25 14:34:43 +02:00
|
|
|
|
2016-09-08 02:12:29 +02:00
|
|
|
//Add the data of the found EmuNAND
|
2016-08-29 15:35:24 +02:00
|
|
|
u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_size, 4),
|
|
|
|
*posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_size, 4);
|
|
|
|
*posOffset = emuOffset;
|
|
|
|
*posHeader = emuHeader;
|
2016-05-25 14:34:43 +02:00
|
|
|
|
|
|
|
//Find and add the SDMMC struct
|
2016-08-29 15:35:24 +02:00
|
|
|
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_size, 4);
|
|
|
|
*posSdmmc = getSdmmc(process9Offset, process9Size);
|
2016-05-25 14:34:43 +02:00
|
|
|
|
2016-09-08 02:12:29 +02:00
|
|
|
//Add EmuNAND hooks
|
2016-08-29 15:35:24 +02:00
|
|
|
u32 branchOffset = (u32)freeK9Space - branchAdditive;
|
|
|
|
patchNandRw(process9Offset, process9Size, branchOffset);
|
2016-05-25 14:34:43 +02:00
|
|
|
|
2016-09-08 02:12:29 +02:00
|
|
|
//Set MPU
|
2016-08-29 15:35:24 +02:00
|
|
|
patchMpu(arm9Section, arm9SectionSize);
|
2015-08-05 03:57:37 +02:00
|
|
|
}
|