Skip to content

Commit 90491af

Browse files
authored
Merge branch 'LumaTeam:master' into master
2 parents 1de852b + 35a7ca2 commit 90491af

14 files changed

Lines changed: 201 additions & 38 deletions

File tree

README.md

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,40 @@
11
# Luma3DS
2-
*Noob-proof (N)3DS "Custom Firmware"*
32

4-
### What it is
5-
**Luma3DS** is a program to patch the system software of (New) Nintendo (2)3DS handheld consoles "on the fly", adding features such as per-game language settings, debugging capabilities for developers, and removing restrictions enforced by Nintendo such as the region lock.
3+
*Nintendo 3DS "Custom Firmware"*
64

7-
It also allows you to run unauthorized ("homebrew") content by removing signature checks.
8-
To use it, you will need a console capable of running homebrew software on the Arm9 processor.
5+
## What it is
6+
**Luma3DS** is a program patching and reimplementing significant parts of the software running on all models of the Nintendo 3DS family of consoles.
97

10-
Since v8.0, Luma3DS has its own in-game menu, triggerable by <kbd>L+Down+Select</kbd> (see the [release notes](https://github.com/LumaTeam/Luma3DS/releases/tag/v8.0)).
8+
It aims at greatly improving the user experience and at supporting the 3DS far beyond its end-of-life. Features include:
119

12-
#
13-
### Compiling
14-
* Prerequisites
15-
1. git
16-
2. [makerom](https://github.com/jakcron/Project_CTR) in PATH
17-
3. [firmtool](https://github.com/TuxSH/firmtool)
18-
4. Up-to-date devkitARM+libctru
19-
1. Clone the repository with `git clone https://github.com/LumaTeam/Luma3DS.git`
20-
2. Run `make`.
10+
* First class support of 3DSX homebrew
11+
* An overlay menu called "Rosalina" (triggerable by <kbd>L+Down+Select</kbd> by default), allowing amongst many thing to take screenshots while in-game
12+
* Removal of restrictions such as the region lock
13+
* Per-game language settings, asset content path redirection (LayeredFS), game plugins...
14+
* A fully-fledged GDB stub allowing to debug software (homebrew and system software alike)
15+
* ... and much more!
2116

22-
The produced `boot.firm` is meant to be copied to the root of your SD card for usage with Boot9Strap.
17+
Luma3DS requires a full-system persisent exploit such as [boot9strap](https://github.com/SciresM/boot9strap) to run.
2318

24-
#
25-
### Setup / Usage / Features
26-
See https://github.com/LumaTeam/Luma3DS/wiki
19+
## Compiling
2720

28-
#
29-
### Credits
30-
See https://github.com/LumaTeam/Luma3DS/wiki/Credits
21+
To build Luma3DS, the following is needed:
22+
* git
23+
* up-to-date devkitARM and libctru
24+
* [makerom](https://github.com/jakcron/Project_CTR) in PATH
25+
* [firmtool](https://github.com/TuxSH/firmtool) installed
3126

32-
#
33-
### Licensing
27+
The produced `boot.firm` is meant to be copied to the root of your SD card for usage with Boot9Strap.
28+
29+
## Setup / Usage / Features
30+
See https://github.com/LumaTeam/Luma3DS/wiki (needs rework)
31+
32+
## Credits
33+
See https://github.com/LumaTeam/Luma3DS/wiki/Credits (needs rework)
34+
35+
## Licensing
3436
This software is licensed under the terms of the GPLv3. You can find a copy of the license in the LICENSE.txt file.
3537

3638
Files in the GDB stub are instead triple-licensed as MIT or "GPLv2 or any later version", in which case it's specified in the file header.
39+
40+
By contributing to this repository, you agree to license your changes to the project's owners.

arm9/data/config_template.ini

250 Bytes
Binary file not shown.

arm9/source/config.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "pin.h"
4040
#include "i2c.h"
4141
#include "ini.h"
42+
#include "firm.h"
4243

4344
#include "config_template_ini.h" // note that it has an extra NUL byte inserted
4445

@@ -566,6 +567,11 @@ static int configIniHandler(void* user, const char* section, const char* name, c
566567
} else {
567568
CHECK_PARSE_OPTION(-1);
568569
}
570+
} else if (strcmp(name, "volume_slider_override") == 0) {
571+
s64 opt;
572+
CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, -1, 100));
573+
cfg->volumeSliderOverride = (s8)opt;
574+
return 1;
569575
} else {
570576
CHECK_PARSE_OPTION(-1);
571577
}
@@ -670,6 +676,7 @@ static size_t saveLumaIniConfigToStr(char *out)
670676
cfg->autobootTwlTitleId, (int)cfg->autobootCtrAppmemtype,
671677

672678
forceAudioOutputStr,
679+
cfg->volumeSliderOverride,
673680

674681
(int)CONFIG(PATCHUNITINFO), (int)CONFIG(DISABLEARM11EXCHANDLERS),
675682
(int)CONFIG(ENABLESAFEFIRMROSALINA)
@@ -774,6 +781,7 @@ bool readConfig(void)
774781
configData.formatVersionMinor = CONFIG_VERSIONMINOR;
775782
configData.config |= 1u << PATCHVERSTRING;
776783
configData.splashDurationMsec = 3000;
784+
configData.volumeSliderOverride = -1;
777785
configData.hbldr3dsxTitleId = HBLDR_DEFAULT_3DSX_TID;
778786
configData.rosalinaMenuCombo = 1u << 9 | 1u << 7 | 1u << 2; // L+Start+Select
779787
configData.topScreenFilter.cct = 6500; // default temp, no-op
@@ -834,8 +842,9 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
834842
"( ) Enable custom upscaling filters for DSi",
835843
"( ) Allow Left+Right / Up+Down combos for DSi",
836844

837-
// Should always be the last entry
838-
"\nSave and exit"
845+
// Should always be the last 2 entries
846+
"\nBoot chainloader",
847+
"Save and exit"
839848
};
840849

841850
static const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
@@ -933,7 +942,10 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
933942
"Commercial software filter these\n"
934943
"combos on their own too, though.",
935944

936-
// Should always be the last entry
945+
946+
// Should always be the last 2 entries
947+
"Boot to the Luma3DS chainloader menu.",
948+
937949
"Save the changes and exit. To discard\n"
938950
"any changes press the POWER button.\n"
939951
"Use START as a shortcut to this entry."
@@ -977,6 +989,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
977989
{ .visible = true },
978990
{ .visible = true },
979991
{ .visible = true },
992+
{ .visible = true },
980993
};
981994

982995
//Calculate the amount of the various kinds of options and pre-select the first single one
@@ -1154,6 +1167,10 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
11541167
startPressed = false;
11551168
break;
11561169
}
1170+
else if (singleSelected == singleOptionsAmount - 2) {
1171+
loadHomebrewFirm(0);
1172+
break;
1173+
}
11571174
else
11581175
{
11591176
bool oldEnabled = singleOptions[singleSelected].enabled;

arm9/source/config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
#define CONFIG_FILE "config.ini"
3838
#define CONFIG_VERSIONMAJOR 3
39-
#define CONFIG_VERSIONMINOR 10
39+
#define CONFIG_VERSIONMINOR 11
4040

4141
#define BOOTCFG_NAND BOOTCONFIG(0, 1)
4242
#define BOOTCFG_EMUINDEX BOOTCONFIG(1, 3)

arm9/source/patches.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
132132
u16 configFormatVersionMajor, configFormatVersionMinor;
133133
u32 config, multiConfig, bootConfig;
134134
u32 splashDurationMsec;
135+
s8 volumeSliderOverride;
135136
u64 hbldr3dsxTitleId;
136137
u32 rosalinaMenuCombo;
137138
u32 pluginLoaderFlags;
@@ -215,6 +216,7 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
215216
info->multiConfig = configData.multiConfig;
216217
info->bootConfig = configData.bootConfig;
217218
info->splashDurationMsec = configData.splashDurationMsec;
219+
info->volumeSliderOverride = configData.volumeSliderOverride;
218220
info->hbldr3dsxTitleId = configData.hbldr3dsxTitleId;
219221
info->rosalinaMenuCombo = configData.rosalinaMenuCombo;
220222
info->pluginLoaderFlags = configData.pluginLoaderFlags;

arm9/source/types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ typedef struct CfgData {
7474

7575
u32 config, multiConfig, bootConfig;
7676
u32 splashDurationMsec;
77+
s8 volumeSliderOverride;
7778

7879
u64 hbldr3dsxTitleId;
7980
u32 rosalinaMenuCombo;

k11_extension/include/globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ typedef struct CfwInfo
150150
u16 configFormatVersionMajor, configFormatVersionMinor;
151151
u32 config, multiConfig, bootConfig;
152152
u32 splashDurationMsec;
153+
s8 volumeSliderOverride;
153154
u64 hbldr3dsxTitleId;
154155
u32 rosalinaMenuCombo;
155156
u32 pluginLoaderFlags;

k11_extension/source/svc/GetSystemInfo.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
6969
case 6:
7070
*out = cfwInfo.splashDurationMsec;
7171
break;
72+
case 7:
73+
*out = (s64)cfwInfo.volumeSliderOverride;
74+
break;
7275
case 0x10:
7376
*out = (s64)cfwInfo.autobootTwlTitleId;
7477
break;

sysmodules/loader/source/patcher.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -579,21 +579,41 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize,
579579
if(!findLayeredFsSymbols(code, textSize, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly) ||
580580
!findLayeredFsPayloadOffset(code, textSize, roSize, dataSize, roAddress, dataAddress, &payloadOffset, &pathOffset, &pathAddress)) return false;
581581

582-
static const char *updateRomFsMounts[] = { "rom2:",
582+
static const char *updateRomFsMounts[] = { "ro2:",
583+
"rom2:",
583584
"rex:",
584585
"patch:",
585586
"ext:",
586587
"rom:" };
587-
u32 updateRomFsIndex;
588588

589-
//Locate update RomFSes
590-
for(updateRomFsIndex = 0; updateRomFsIndex < sizeof(updateRomFsMounts) / sizeof(char *) - 1; updateRomFsIndex++)
589+
bool isMarioKart7 = (u32)progId == 0x00030600 || //JPN MK7
590+
(u32)progId == 0x00030700 || //EUR MK7
591+
(u32)progId == 0x00030800 || //USA MK7
592+
(u32)progId == 0x00030A00 || //KOR MK7
593+
(u32)progId == 0x0008B400; //TWN MK7
594+
// Exclude CHN as it never got updates
595+
596+
const char *updateRomFsMount;
597+
598+
if (isMarioKart7)
599+
{
600+
updateRomFsMount = "pat1"; // Isolated to prevent false-positives
601+
}
602+
603+
else
591604
{
592-
u32 patternSize = strlen(updateRomFsMounts[updateRomFsIndex]);
593-
u8 temp[7];
594-
temp[0] = 0;
595-
memcpy(temp + 1, updateRomFsMounts[updateRomFsIndex], patternSize);
596-
if(memsearch(code, temp, size, patternSize + 1) != NULL) break;
605+
u32 updateRomFsIndex;
606+
607+
//Locate update RomFS
608+
for(updateRomFsIndex = 0; updateRomFsIndex < sizeof(updateRomFsMounts) / sizeof(char *) - 1; updateRomFsIndex++)
609+
{
610+
u32 patternSize = strlen(updateRomFsMounts[updateRomFsIndex]);
611+
u8 temp[7];
612+
temp[0] = 0;
613+
memcpy(temp + 1, updateRomFsMounts[updateRomFsIndex], patternSize);
614+
if(memsearch(code, temp, size, patternSize + 1) != NULL) break;
615+
}
616+
updateRomFsMount = updateRomFsMounts[updateRomFsIndex];
597617
}
598618

599619
//Setup the payload
@@ -607,7 +627,7 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize,
607627
romfsRedirPatchFsMountArchive = 0x100000 + fsMountArchive;
608628
romfsRedirPatchFsRegisterArchive = 0x100000 + fsRegisterArchive;
609629
romfsRedirPatchArchiveId = archiveId;
610-
memcpy(&romfsRedirPatchUpdateRomFsMount, updateRomFsMounts[updateRomFsIndex], 4);
630+
memcpy(&romfsRedirPatchUpdateRomFsMount, updateRomFsMount, 4);
611631

612632
memcpy(payload, romfsRedirPatch, romfsRedirPatchSize);
613633

250 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)