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/main.c

273 lines
9.1 KiB
C

/*
* 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.
*/
#include "config.h"
#include "emunand.h"
#include "fs.h"
#include "firm.h"
#include "utils.h"
#include "exceptions.h"
#include "draw.h"
#include "strings.h"
#include "buttons.h"
#include "pin.h"
extern CfgData configData;
extern FirmwareSource firmSource;
void main(void)
{
bool isA9lhInstalled,
isSafeMode = false;
u32 configTemp,
emuHeader;
FirmwareType firmType;
FirmwareSource nandType;
ConfigurationStatus needConfig;
//Mount SD or CTRNAND
bool isSdMode;
if(mountFs(true, false)) isSdMode = true;
else
{
firmSource = FIRMWARE_SYSNAND;
if(!mountFs(false, true)) error("Failed to mount SD and CTRNAND.");
isSdMode = false;
}
//Attempt to read the configuration file
needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
//Determine if this is a firmlaunch boot
if(ISFIRMLAUNCH)
{
if(needConfig == CREATE_CONFIGURATION) mcuPowerOff();
switch(launchedFirmTidLow[7])
{
case u'2':
firmType = (FirmwareType)(launchedFirmTidLow[5] - u'0');
break;
case u'3':
firmType = SAFE_FIRM;
break;
case u'1':
firmType = SYSUPDATER_FIRM;
break;
}
nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = (FirmwareSource)BOOTCFG_FIRM;
isA9lhInstalled = BOOTCFG_A9LH != 0;
}
else
{
if(ISA9LH)
{
detectAndProcessExceptionDumps();
installArm9Handlers();
}
firmType = NATIVE_FIRM;
isA9lhInstalled = ISA9LH;
//Get pressed buttons
u32 pressed = HID_PAD;
//Save old options and begin saving the new boot configuration
configTemp = (configData.config & 0xFFFFFF00) | ((u32)ISA9LH << 6);
//If it's a MCU reboot, try to force boot options
if(ISA9LH && CFG_BOOTENV && needConfig != CREATE_CONFIGURATION)
{
//Always force a SysNAND boot when quitting AGB_FIRM
if(CFG_BOOTENV == 7)
{
nandType = FIRMWARE_SYSNAND;
firmSource = (BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM;
needConfig = DONT_CONFIGURE;
//Flag to prevent multiple boot options-forcing
configTemp |= 1 << 7;
}
/* Else, force the last used boot options unless a button is pressed
or the no-forcing flag is set */
else if(!pressed && !BOOTCFG_NOFORCEFLAG)
{
nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = (FirmwareSource)BOOTCFG_FIRM;
needConfig = DONT_CONFIGURE;
}
}
//Boot options aren't being forced
if(needConfig != DONT_CONFIGURE)
{
u32 pinMode = MULTICONFIG(PIN);
bool pinExists = pinMode != 0 && verifyPin(pinMode);
//If no configuration file exists or SELECT is held, load configuration menu
bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & (BUTTON_SELECT | BUTTON_L1)) == BUTTON_SELECT);
if(shouldLoadConfigMenu)
{
configMenu(isSdMode, pinExists, pinMode);
//Update pressed buttons
pressed = HID_PAD;
}
if(ISA9LH && !CFG_BOOTENV && pressed == SAFE_MODE)
{
nandType = FIRMWARE_SYSNAND;
firmSource = FIRMWARE_SYSNAND;
isSafeMode = true;
//If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo
if(pinExists && !shouldLoadConfigMenu)
{
while(HID_PAD & PIN_BUTTONS);
wait(false, 2ULL);
}
}
else
{
u32 splashMode = MULTICONFIG(SPLASH);
if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START)
{
payloadMenu();
pressed = HID_PAD;
}
else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL);
if(splashMode == 2) loadSplash();
//If booting from CTRNAND, always use SysNAND
if(!isSdMode) nandType = FIRMWARE_SYSNAND;
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
else if(pressed & BUTTON_R1)
{
if(CONFIG(USESYSFIRM))
{
nandType = FIRMWARE_EMUNAND;
firmSource = FIRMWARE_SYSNAND;
}
else
{
nandType = FIRMWARE_SYSNAND;
firmSource = FIRMWARE_EMUNAND;
}
}
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
with their own FIRM */
else firmSource = nandType = (CONFIG(AUTOBOOTSYS) == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
//If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config
if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
{
FirmwareSource tempNand;
switch(pressed & DPAD_BUTTONS)
{
case BUTTON_UP:
tempNand = FIRMWARE_EMUNAND;
break;
case BUTTON_RIGHT:
tempNand = FIRMWARE_EMUNAND2;
break;
case BUTTON_DOWN:
tempNand = FIRMWARE_EMUNAND3;
break;
case BUTTON_LEFT:
tempNand = FIRMWARE_EMUNAND4;
break;
default:
tempNand = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU));
break;
}
if(nandType == FIRMWARE_EMUNAND) nandType = tempNand;
else firmSource = tempNand;
}
}
}
}
//If we need to boot EmuNAND, make sure it exists
if(nandType != FIRMWARE_SYSNAND)
{
locateEmuNand(&emuHeader, &nandType);
if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND;
}
//Same if we're using EmuNAND as the FIRM source
else if(firmSource != FIRMWARE_SYSNAND)
locateEmuNand(&emuHeader, &firmSource);
if(!ISFIRMLAUNCH)
{
configTemp |= (u32)nandType | ((u32)firmSource << 3);
writeConfig(needConfig, configTemp);
}
if(isSdMode && !mountFs(false, false)) error("Failed to mount CTRNAND.");
bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES);
u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, isSafeMode);
u32 devMode = MULTICONFIG(DEVOPTIONS);
u32 res;
switch(firmType)
{
case NATIVE_FIRM:
res = patchNativeFirm(firmVersion, nandType, emuHeader, isA9lhInstalled, isSafeMode, devMode);
break;
case TWL_FIRM:
res = patchTwlFirm(firmVersion, devMode);
break;
case AGB_FIRM:
res = patchAgbFirm(devMode);
break;
case SAFE_FIRM:
case SYSUPDATER_FIRM:
case NATIVE_FIRM1X2X:
res = isA9lhInstalled ? patch1x2xNativeAndSafeFirm(devMode) : 0;
break;
}
if(res != 0)
{
char patchesError[] = "Failed to apply FIRM patch(es).";
decItoa(res, patchesError + 16, 2);
error(patchesError);
}
launchFirm(firmType, loadFromStorage);
}