This repository has been archived on 2022-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
Luma3DS-3GX/source/emunand.c

219 lines
6.1 KiB
C
Raw Normal View History

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"
#include "memory.h"
2015-08-05 03:57:37 +02:00
#include "fatfs/sdmmc/sdmmc.h"
2016-09-23 02:06:04 +02:00
#include "../build/bundled.h"
2015-08-05 03:57:37 +02:00
u32 emuOffset;
2016-09-08 02:12:29 +02:00
void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
{
static u8 __attribute__((aligned(4))) temp[0x200];
static u32 nandSize = 0,
fatStart;
2016-09-07 18:04:31 +02:00
bool found = false;
2016-09-22 22:19:27 +02:00
if(!nandSize)
{
nandSize = getMMCDevice(0)->total_size;
2016-09-22 22:19:27 +02:00
sdmmc_sdcard_readsectors(0, 1, temp);
fatStart = *(u32 *)(temp + 0x1C6); //First sector of the FAT partition
}
2016-09-12 13:19:59 +02:00
for(u32 i = 0; i < 3 && !found; i++)
2016-09-07 18:04:31 +02:00
{
static const u32 roundedMinsizes[] = {0x1D8000, 0x26E000};
2016-09-07 18:04:31 +02:00
u32 nandOffset;
switch(i)
{
case 1:
nandOffset = ROUND_TO_4MB(nandSize + 1); //"Default" layout
2016-09-07 18:04:31 +02:00
break;
case 2:
nandOffset = roundedMinsizes[ISN3DS ? 1 : 0]; //"Minsize" layout
2016-09-07 18:04:31 +02:00
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);
if(fatStart >= nandOffset + roundedMinsizes[ISN3DS ? 1 : 0])
2016-09-07 18:04:31 +02:00
{
//Check for RedNAND
if(!sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) && memcmp(temp + 0x100, "NCSD", 4) == 0)
{
emuOffset = nandOffset + 1;
*emuHeader = nandOffset + 1;
found = true;
}
2016-09-07 18:04:31 +02:00
//Check for Gateway EmuNAND
else if(i != 2 && !sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) && memcmp(temp + 0x100, "NCSD", 4) == 0)
{
emuOffset = nandOffset;
*emuHeader = nandOffset + nandSize;
found = true;
}
2016-09-07 18:04:31 +02:00
}
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
}
}
static inline u32 getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space)
2016-05-25 15:26:51 +02:00
{
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
2016-10-10 23:46:25 +02:00
u32 ret;
2016-05-25 15:26:51 +02:00
//Looking for the last free space before Process9
2016-10-10 23:46:25 +02:00
*freeK9Space = memsearch(pos, pattern, size, sizeof(pattern));
if(*freeK9Space == NULL) ret = 1;
else
{
*freeK9Space += 0x455;
ret = 0;
}
2016-10-10 23:46:25 +02:00
return ret;
2016-05-25 15:26:51 +02:00
}
static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc)
{
//Look for struct code
2016-03-26 19:21:17 +01:00
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
u32 ret;
const u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1;
else
{
*sdmmc = *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
2016-10-10 23:46:25 +02:00
ret = 0;
}
return ret;
}
static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset)
{
//Look for read/write code
2016-03-26 19:21:17 +01:00
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
2016-10-10 23:46:25 +02:00
u32 ret;
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(readOffset == NULL) ret = 1;
else
{
readOffset -= 3;
u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern));
2016-02-08 03:37:03 +01:00
if(writeOffset == NULL) ret = 1;
else
{
writeOffset -= 3;
*readOffset = *writeOffset = 0x4C00;
readOffset[1] = writeOffset[1] = 0x47A0;
((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset;
2016-10-10 23:46:25 +02:00
ret = 0;
}
}
2016-05-25 15:26:51 +02:00
return ret;
2016-02-08 03:37:03 +01:00
}
static inline u32 patchMpu(u8 *pos, u32 size)
{
//Look for MPU pattern
2016-03-26 19:21:17 +01:00
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
u32 ret;
2016-02-08 03:37:03 +01:00
2016-10-23 03:42:52 +02:00
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1;
else
{
2016-10-23 03:42:52 +02:00
off[1] = 0x0036;
2016-10-23 04:03:41 +02:00
off[0xC] = off[0x12] = 0x0603;
2016-10-10 23:46:25 +02:00
ret = 0;
}
return ret;
}
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u32 emuHeader, u8 *kernel9Address)
{
u32 ret = 0;
u8 *freeK9Space;
ret += getFreeK9Space(arm9Section, kernel9Size, &freeK9Space);
2016-10-10 23:46:25 +02:00
if(!ret)
{
2016-10-10 23:46:25 +02:00
//Copy EmuNAND code
memcpy(freeK9Space, emunand_bin, emunand_bin_size);
//Add the data of the found EmuNAND
u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_bin_size, 4),
*posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_bin_size, 4);
*posOffset = emuOffset;
*posHeader = emuHeader;
//Find and add the SDMMC struct
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4);
u32 sdmmc;
ret += getSdmmc(process9Offset, process9Size, &sdmmc);
if(!ret) *posSdmmc = sdmmc;
//Add EmuNAND hooks
2016-10-11 00:41:58 +02:00
u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address);
ret += patchNandRw(process9Offset, process9Size, branchOffset);
//Set MPU
ret += patchMpu(arm9Section, kernel9Size);
}
return ret;
2015-08-05 03:57:37 +02:00
}