mirror of
https://github.com/LumaTeam/Luma3DS.git
synced 2026-02-22 09:54:38 +00:00
Compare commits
No commits in common. "master" and "v13.3" have entirely different histories.
@ -195,28 +195,6 @@ static void deinitScreens(void)
|
|||||||
*(vu32 *)0x10202014 = 0;
|
*(vu32 *)0x10202014 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zerofillN3dsAblRegisters(void)
|
|
||||||
{
|
|
||||||
// It should be fine to write to these regs even on O3DS as they
|
|
||||||
// are RAZ/WI
|
|
||||||
|
|
||||||
// TODO: read from calibration, but null values should do just
|
|
||||||
// fine. From testing, LUT explicitly ignores null values, and
|
|
||||||
// it is probably the case of reg @ 0x54 as well.
|
|
||||||
*(vu32 *)0x10202250 = 0; // unknown 24-bit value, seen: 0
|
|
||||||
*(vu32 *)0x10202254 = 0; // unknown 24-bit value, seen: nonzero
|
|
||||||
|
|
||||||
*(vu32 *)0x10202A50 = 0; // unknown 24-bit value, seen: 0
|
|
||||||
*(vu32 *)0x10202A54 = 0; // unknown 24-bit value, seen: nonzero
|
|
||||||
|
|
||||||
for (u32 i = 0; i < 64; i++) {
|
|
||||||
// Blend colors (w/ color multiplication) for each group
|
|
||||||
// of 4 relative-luminance Rs
|
|
||||||
*(vu32 *)(0x10202300 + 4*i) = 0;
|
|
||||||
*(vu32 *)(0x10202B00 + 4*i) = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
operation = ARM11_READY;
|
operation = ARM11_READY;
|
||||||
@ -245,9 +223,6 @@ void main(void)
|
|||||||
case DEINIT_SCREENS:
|
case DEINIT_SCREENS:
|
||||||
deinitScreens();
|
deinitScreens();
|
||||||
break;
|
break;
|
||||||
case ZEROFILL_N3DS_ABL_REGISTERS:
|
|
||||||
zerofillN3dsAblRegisters();
|
|
||||||
break;
|
|
||||||
case PREPARE_ARM11_FOR_FIRMLAUNCH:
|
case PREPARE_ARM11_FOR_FIRMLAUNCH:
|
||||||
memcpy((void *)0x1FFFFC00, (void *)prepareForFirmlaunch, prepareForFirmlaunchSize);
|
memcpy((void *)0x1FFFFC00, (void *)prepareForFirmlaunch, prepareForFirmlaunchSize);
|
||||||
*(vu32 *)0x1FFFFFFC = 0;
|
*(vu32 *)0x1FFFFFFC = 0;
|
||||||
|
|||||||
@ -60,7 +60,6 @@ typedef enum
|
|||||||
SWAP_FRAMEBUFFERS,
|
SWAP_FRAMEBUFFERS,
|
||||||
UPDATE_BRIGHTNESS,
|
UPDATE_BRIGHTNESS,
|
||||||
DEINIT_SCREENS,
|
DEINIT_SCREENS,
|
||||||
ZEROFILL_N3DS_ABL_REGISTERS,
|
|
||||||
PREPARE_ARM11_FOR_FIRMLAUNCH,
|
PREPARE_ARM11_FOR_FIRMLAUNCH,
|
||||||
ARM11_READY,
|
ARM11_READY,
|
||||||
} Arm11Operation;
|
} Arm11Operation;
|
||||||
|
|||||||
@ -694,7 +694,7 @@ static size_t saveLumaIniConfigToStr(char *out)
|
|||||||
return n < 0 ? 0 : (size_t)n;
|
return n < 0 ? 0 : (size_t)n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char tmpIniBuffer[0x2000 + 0x400]; // eyeballed. TODO use #embed
|
static char tmpIniBuffer[0x2000];
|
||||||
|
|
||||||
static bool readLumaIniConfig(void)
|
static bool readLumaIniConfig(void)
|
||||||
{
|
{
|
||||||
@ -709,13 +709,6 @@ static bool readLumaIniConfig(void)
|
|||||||
static bool writeLumaIniConfig(void)
|
static bool writeLumaIniConfig(void)
|
||||||
{
|
{
|
||||||
size_t n = saveLumaIniConfigToStr(tmpIniBuffer);
|
size_t n = saveLumaIniConfigToStr(tmpIniBuffer);
|
||||||
|
|
||||||
// FIXME: this is UB we should port snprintf sometime (as well as fix other tech debt)
|
|
||||||
if (n + 1 >= sizeof(tmpIniBuffer)) {
|
|
||||||
error("Configuration data buffer overflow, please report this issue");
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
return n != 0 && fileWrite(tmpIniBuffer, "config.ini", n);
|
return n != 0 && fileWrite(tmpIniBuffer, "config.ini", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,7 +30,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "screen.h"
|
|
||||||
|
|
||||||
u8 *loadDeliverArg(void)
|
u8 *loadDeliverArg(void)
|
||||||
{
|
{
|
||||||
@ -72,7 +71,7 @@ u8 *loadDeliverArg(void)
|
|||||||
bool hasMagic = memcmp(tlnc, "TLNC", 4) == 0;
|
bool hasMagic = memcmp(tlnc, "TLNC", 4) == 0;
|
||||||
u8 crcLen = tlnc[5];
|
u8 crcLen = tlnc[5];
|
||||||
u16 crc = *(u16 *)(tlnc + 6);
|
u16 crc = *(u16 *)(tlnc + 6);
|
||||||
if (!hasMagic || (8 + crcLen) > 0x100 || crc != crc16(tlnc + 8, crcLen, 0xFFFF))
|
if (!hasMagic || crcLen <= 248 || crc != crc16(tlnc + 8, crcLen, 0xFFFF))
|
||||||
memset(tlnc, 0, 0x100);
|
memset(tlnc, 0, 0x100);
|
||||||
|
|
||||||
memset(deliverArg + 0x400, 0, 0xC00);
|
memset(deliverArg + 0x400, 0, 0xC00);
|
||||||
@ -142,8 +141,6 @@ static bool configureHomebrewAutobootCtr(u8 *deliverArg)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
u8 memtype = configData.autobootCtrAppmemtype;
|
u8 memtype = configData.autobootCtrAppmemtype;
|
||||||
// autobootCtrAppmemtype already checked, but it doesn't hurt to check again
|
|
||||||
memtype = memtype >= 5 ? 0 : memtype;
|
|
||||||
deliverArg[0x400] = ISN3DS ? appmemtypesN3ds[memtype] : appmemtypesO3ds[memtype];
|
deliverArg[0x400] = ISN3DS ? appmemtypesN3ds[memtype] : appmemtypesO3ds[memtype];
|
||||||
|
|
||||||
// Determine whether to load from the SD card or from NAND. We don't support gamecards for this
|
// Determine whether to load from the SD card or from NAND. We don't support gamecards for this
|
||||||
@ -201,29 +198,6 @@ static bool configureHomebrewAutobootTwl(u8 *deliverArg)
|
|||||||
|
|
||||||
*(u16 *)(tlnc + 6) = crc16(tlnc + 8, 0x18, 0xFFFF);
|
*(u16 *)(tlnc + 6) = crc16(tlnc + 8, 0x18, 0xFFFF);
|
||||||
|
|
||||||
// Even though (when running TWL/AGB FIRM) the SoC is in O3DS mode, and the GPU also is,
|
|
||||||
// as well as most other components behaving as such (external RAM, L2C not usable, etc.),
|
|
||||||
// this is NOT the case for the LCD and adaptive backlight logic which retains FULL N3DS
|
|
||||||
// functionality, including a feature where the window is blended with a given color depending
|
|
||||||
// on the overall relative luminance of that window.
|
|
||||||
|
|
||||||
// However, Nintendo's own code mistakenly assumes the opposite, and clearly so ("if GPU in N3DS mode"
|
|
||||||
// checks, not passing N3DS extra adaptive backlight (ABL) to TWL/AGB_FIRM). This has implications:
|
|
||||||
|
|
||||||
// - Powersaving (ABL) settings in TWL/AGB_FIRM is inconsistent with *both* O3DS (because the new RGB blend LUT
|
|
||||||
// has been set to its current value by NATIVE_FIRM) and N3DS (because "pwn_cnt" and "inertia" are missing
|
|
||||||
// their N3DS-only bits)
|
|
||||||
// - "rave party" when booting into TWL/AGB_FIRM or O3DS NATIVE_FIRM without these regs (well, the LUT) initialized.
|
|
||||||
// Easiest way to do so is by leveraging the "DSi autooboot" feature Luma provides. It is worth noting at least
|
|
||||||
// the LUT survives hardware reboots (if Nintendo were using DSi software that was using TLNC-based reboots,
|
|
||||||
// they wouldn't have noticed).
|
|
||||||
|
|
||||||
// As such, zerofill these registers (from testing, hardware explicitly discards null values, so this
|
|
||||||
// should be fine). For now, only touch the Luma-initiated autoboot path
|
|
||||||
|
|
||||||
if (ISN3DS)
|
|
||||||
zerofillN3dsAblRegisters();
|
|
||||||
|
|
||||||
CFG_BOOTENV = 3;
|
CFG_BOOTENV = 3;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -137,7 +137,6 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
|
|||||||
return result == FR_OK && (u32)written == size;
|
return result == FR_OK && (u32)written == size;
|
||||||
}
|
}
|
||||||
case FR_NO_PATH:
|
case FR_NO_PATH:
|
||||||
// Only create the last dir in the hierarchy
|
|
||||||
for(u32 i = 1; path[i] != 0; i++)
|
for(u32 i = 1; path[i] != 0; i++)
|
||||||
if(path[i] == '/')
|
if(path[i] == '/')
|
||||||
{
|
{
|
||||||
@ -179,7 +178,6 @@ bool fileCopy(const char *pathSrc, const char *pathDst, bool replace, void *tmpB
|
|||||||
}
|
}
|
||||||
else if (res == FR_NO_PATH)
|
else if (res == FR_NO_PATH)
|
||||||
{
|
{
|
||||||
// Only create the last dir in the hierarchy
|
|
||||||
const char *c;
|
const char *c;
|
||||||
for (c = pathDst + strlen(pathDst); *c != '/' && c >= pathDst; --c);
|
for (c = pathDst + strlen(pathDst); *c != '/' && c >= pathDst; --c);
|
||||||
if (c >= pathDst && c - pathDst <= FF_MAX_LFN && *c != '\0')
|
if (c >= pathDst && c - pathDst <= FF_MAX_LFN && *c != '\0')
|
||||||
@ -443,38 +441,21 @@ static bool backupEssentialFiles(void)
|
|||||||
{
|
{
|
||||||
size_t sz = sizeof(fileCopyBuffer);
|
size_t sz = sizeof(fileCopyBuffer);
|
||||||
|
|
||||||
u32 deviceID = *(vu32*)0x01FFB804;
|
|
||||||
char pathStart[0x20];
|
|
||||||
sprintf(pathStart, "backups/%08lX/", deviceID);
|
|
||||||
char fullPath[0x80];
|
|
||||||
|
|
||||||
// Since the other funcs in this file don't create directories recursively (only the last one),
|
|
||||||
// and nor does f_mkdir, create the directories anyway and ignore the result
|
|
||||||
f_mkdir("backups");
|
|
||||||
f_mkdir(pathStart);
|
|
||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
sprintf(fullPath, "%sHWCAL0.dat", pathStart);
|
ok = ok && fileCopy("nand:/ro/sys/HWCAL0.dat", "backups/HWCAL0.dat", false, fileCopyBuffer, sz);
|
||||||
ok = ok && fileCopy("nand:/ro/sys/HWCAL0.dat", fullPath, false, fileCopyBuffer, sz);
|
ok = ok && fileCopy("nand:/ro/sys/HWCAL1.dat", "backups/HWCAL1.dat", false, fileCopyBuffer, sz);
|
||||||
sprintf(fullPath, "%sHWCAL1.dat", pathStart);
|
|
||||||
ok = ok && fileCopy("nand:/ro/sys/HWCAL1.dat", fullPath, false, fileCopyBuffer, sz);
|
|
||||||
|
|
||||||
sprintf(fullPath, "%sLocalFriendCodeSeed_A", pathStart);
|
ok = ok && fileCopy("nand:/rw/sys/LocalFriendCodeSeed_A", "backups/LocalFriendCodeSeed_A", false, fileCopyBuffer, sz); // often doesn't exist
|
||||||
ok = ok && fileCopy("nand:/rw/sys/LocalFriendCodeSeed_A", fullPath, false, fileCopyBuffer, sz); // often doesn't exist
|
ok = ok && fileCopy("nand:/rw/sys/LocalFriendCodeSeed_B", "backups/LocalFriendCodeSeed_B", false, fileCopyBuffer, sz);
|
||||||
sprintf(fullPath, "%sLocalFriendCodeSeed_B", pathStart);
|
|
||||||
ok = ok && fileCopy("nand:/rw/sys/LocalFriendCodeSeed_B", fullPath, false, fileCopyBuffer, sz);
|
|
||||||
|
|
||||||
sprintf(fullPath, "%sSecureInfo_A", pathStart);
|
ok = ok && fileCopy("nand:/rw/sys/SecureInfo_A", "backups/SecureInfo_A", false, fileCopyBuffer, sz);
|
||||||
ok = ok && fileCopy("nand:/rw/sys/SecureInfo_A", fullPath, false, fileCopyBuffer, sz);
|
ok = ok && fileCopy("nand:/rw/sys/SecureInfo_B", "backups/SecureInfo_B", false, fileCopyBuffer, sz); // often doesn't exist
|
||||||
sprintf(fullPath, "%sSecureInfo_B", pathStart);
|
|
||||||
ok = ok && fileCopy("nand:/rw/sys/SecureInfo_B", fullPath, false, fileCopyBuffer, sz); // often doesn't exist
|
|
||||||
|
|
||||||
if (!ok) return false;
|
if (!ok) return false;
|
||||||
|
|
||||||
alignedseqmemcpy(fileCopyBuffer, (const void *)0x10012000, 0x100);
|
alignedseqmemcpy(fileCopyBuffer, (const void *)0x10012000, 0x100);
|
||||||
sprintf(fullPath, "%sotp.bin", pathStart);
|
if (getFileSize("backups/otp.bin") != 0x100)
|
||||||
if (getFileSize(fullPath) != 0x100)
|
ok = ok && fileWrite(fileCopyBuffer, "backups/otp.bin", 0x100);
|
||||||
ok = ok && fileWrite(fileCopyBuffer, fullPath, 0x100);
|
|
||||||
|
|
||||||
if (!ok) return false;
|
if (!ok) return false;
|
||||||
|
|
||||||
@ -482,22 +463,19 @@ static bool backupEssentialFiles(void)
|
|||||||
u8 c = mcuConsoleInfo[0];
|
u8 c = mcuConsoleInfo[0];
|
||||||
if (c == 2 || c == 4 || (ISN3DS && c == 5) || c == 6)
|
if (c == 2 || c == 4 || (ISN3DS && c == 5) || c == 6)
|
||||||
{
|
{
|
||||||
sprintf(fullPath, "%sHWCAL_01_EEPROM.dat", pathStart);
|
|
||||||
I2C_readRegBuf(I2C_DEV_EEPROM, 0, fileCopyBuffer, 0x1000); // Up to two instances of hwcal, with the second one @0x800
|
I2C_readRegBuf(I2C_DEV_EEPROM, 0, fileCopyBuffer, 0x1000); // Up to two instances of hwcal, with the second one @0x800
|
||||||
if (getFileSize(fullPath) != 0x1000)
|
if (getFileSize("backups/HWCAL_01_EEPROM.dat") != 0x1000)
|
||||||
ok = ok && fileWrite(fileCopyBuffer, fullPath, 0x1000);
|
ok = ok && fileWrite(fileCopyBuffer, "backups/HWCAL_01_EEPROM.dat", 0x1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// B9S bootrom backups
|
// B9S bootrom backups
|
||||||
u32 hash[32/4];
|
u32 hash[32/4];
|
||||||
sha(hash, (const void *)0x08080000, 0x10000, SHA_256_MODE);
|
sha(hash, (const void *)0x08080000, 0x10000, SHA_256_MODE);
|
||||||
sprintf(fullPath, "%sboot9.bin", pathStart);
|
if (memcmp(hash, boot9Sha256, 32) == 0 && getFileSize("backups/boot9.bin") != 0x10000)
|
||||||
if (memcmp(hash, boot9Sha256, 32) == 0 && getFileSize(fullPath) != 0x10000)
|
ok = ok && fileWrite((const void *)0x08080000, "backups/boot9.bin", 0x10000);
|
||||||
ok = ok && fileWrite((const void *)0x08080000, fullPath, 0x10000);
|
|
||||||
sha(hash, (const void *)0x08090000, 0x10000, SHA_256_MODE);
|
sha(hash, (const void *)0x08090000, 0x10000, SHA_256_MODE);
|
||||||
sprintf(fullPath, "%sboot11.bin", pathStart);
|
if (memcmp(hash, boot11Sha256, 32) == 0 && getFileSize("backups/boot11.bin") != 0x10000)
|
||||||
if (memcmp(hash, boot11Sha256, 32) == 0 && getFileSize(fullPath) != 0x10000)
|
ok = ok && fileWrite((const void *)0x08090000, "backups/boot11.bin", 0x10000);
|
||||||
ok = ok && fileWrite((const void *)0x08090000, fullPath, 0x10000);
|
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,8 +40,6 @@ typedef enum
|
|||||||
I2C_DEV_CAMERA = 1, // Unconfirmed
|
I2C_DEV_CAMERA = 1, // Unconfirmed
|
||||||
I2C_DEV_CAMERA2 = 2, // Unconfirmed
|
I2C_DEV_CAMERA2 = 2, // Unconfirmed
|
||||||
I2C_DEV_MCU = 3,
|
I2C_DEV_MCU = 3,
|
||||||
I2C_DEV_LCD_TOP = 5,
|
|
||||||
I2C_DEV_LCD_BOT = 6,
|
|
||||||
I2C_DEV_GYRO = 10,
|
I2C_DEV_GYRO = 10,
|
||||||
I2C_DEV_DEBUG_PAD = 12,
|
I2C_DEV_DEBUG_PAD = 12,
|
||||||
I2C_DEV_IR = 13,
|
I2C_DEV_IR = 13,
|
||||||
|
|||||||
@ -843,24 +843,6 @@ u32 patchLgyK11(u8 *section1, u32 section1Size, u8 *section2, u32 section2Size)
|
|||||||
return 1;
|
return 1;
|
||||||
*off2 = 0xE01A;
|
*off2 = 0xE01A;
|
||||||
|
|
||||||
// Patch kernelpanic to skip devunit check, so that it sets the LCD fill regs
|
|
||||||
// which are useful to detect such panics
|
|
||||||
u16 *off3;
|
|
||||||
for (off3 = (u16 *)section1; (u8 *)off3 <= section1 + section1Size && (off3[0] != 0x481D || off3[1] != 0xB570); off3++);
|
|
||||||
if ((u8 *)off3 >= section1 + section1Size)
|
|
||||||
return 1;
|
|
||||||
off3[2] = 0x2001; // movs r0, #1
|
|
||||||
|
|
||||||
// Patch kernel to avoid allocating the two "configuration memory" pages, freeing
|
|
||||||
// 0x2000 bytes of kernel "heap" (which is 0xD000 AXIWRAM bytes on LGY K11 instead
|
|
||||||
// of the entire FCRAM on NFIRM). This is indeed a bug because if prevents two of the
|
|
||||||
// 12 KThread objects from being created
|
|
||||||
u16 *off4;
|
|
||||||
for (off4 = (u16 *)section1; (u8 *)off4 <= section1 + section1Size && (off4[0] != 0xB570 || off4[1] != 0x2200); off4++);
|
|
||||||
if ((u8 *)off4 >= section1 + section1Size)
|
|
||||||
return 1;
|
|
||||||
*off4 = 0x4770; // bx lr
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -70,14 +70,6 @@ void prepareArm11ForFirmlaunch(void)
|
|||||||
void deinitScreens(void)
|
void deinitScreens(void)
|
||||||
{
|
{
|
||||||
if(ARESCREENSINITIALIZED) invokeArm11Function(DEINIT_SCREENS);
|
if(ARESCREENSINITIALIZED) invokeArm11Function(DEINIT_SCREENS);
|
||||||
|
|
||||||
// Backlight voltage off
|
|
||||||
I2C_writeReg(I2C_DEV_MCU, 0x22, 0x14);
|
|
||||||
wait(50);
|
|
||||||
|
|
||||||
// LCD panel voltage off
|
|
||||||
I2C_writeReg(I2C_DEV_MCU, 0x22, 0x01);
|
|
||||||
wait(50);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateBrightness(u32 brightnessIndex)
|
void updateBrightness(u32 brightnessIndex)
|
||||||
@ -110,31 +102,8 @@ void initScreens(void)
|
|||||||
memcpy((void *)(ARM11_PARAMETERS_ADDRESS + 4), fbs, sizeof(fbs));
|
memcpy((void *)(ARM11_PARAMETERS_ADDRESS + 4), fbs, sizeof(fbs));
|
||||||
invokeArm11Function(INIT_SCREENS);
|
invokeArm11Function(INIT_SCREENS);
|
||||||
|
|
||||||
// Fragile code, needs proper fix/total rewrite of the baremetal components anyway
|
//Turn on backlight
|
||||||
// Assume controller revision is not 0x00 for either screen (this revision is extremely
|
I2C_writeReg(I2C_DEV_MCU, 0x22, 0x2A);
|
||||||
// old and shouldn't be seen in retail units nor normal devunits)
|
|
||||||
|
|
||||||
// Controller reset off
|
|
||||||
I2C_writeReg(I2C_DEV_LCD_TOP, 0xFE, 0xAA);
|
|
||||||
I2C_writeReg(I2C_DEV_LCD_BOT, 0xFE, 0xAA);
|
|
||||||
wait(5);
|
|
||||||
|
|
||||||
// Controller power on
|
|
||||||
I2C_writeReg(I2C_DEV_LCD_TOP, 0x01, 0x10);
|
|
||||||
I2C_writeReg(I2C_DEV_LCD_BOT, 0x01, 0x10);
|
|
||||||
wait(5);
|
|
||||||
|
|
||||||
// Clear error flag
|
|
||||||
I2C_writeReg(I2C_DEV_LCD_TOP, 0x60, 0x00);
|
|
||||||
I2C_writeReg(I2C_DEV_LCD_BOT, 0x60, 0x00);
|
|
||||||
wait(5);
|
|
||||||
|
|
||||||
// LCD panel (bias ?) voltage on
|
|
||||||
I2C_writeReg(I2C_DEV_MCU, 0x22, 0x02);
|
|
||||||
wait(50);
|
|
||||||
|
|
||||||
// Backlight voltage on
|
|
||||||
I2C_writeReg(I2C_DEV_MCU, 0x22, 0x28);
|
|
||||||
wait(5);
|
wait(5);
|
||||||
}
|
}
|
||||||
else updateBrightness(MULTICONFIG(BRIGHTNESS));
|
else updateBrightness(MULTICONFIG(BRIGHTNESS));
|
||||||
@ -149,8 +118,3 @@ void initScreens(void)
|
|||||||
clearScreens(false);
|
clearScreens(false);
|
||||||
swapFramebuffers(false);
|
swapFramebuffers(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void zerofillN3dsAblRegisters(void)
|
|
||||||
{
|
|
||||||
invokeArm11Function(ZEROFILL_N3DS_ABL_REGISTERS);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -59,7 +59,6 @@ typedef enum
|
|||||||
SWAP_FRAMEBUFFERS,
|
SWAP_FRAMEBUFFERS,
|
||||||
UPDATE_BRIGHTNESS,
|
UPDATE_BRIGHTNESS,
|
||||||
DEINIT_SCREENS,
|
DEINIT_SCREENS,
|
||||||
ZEROFILL_N3DS_ABL_REGISTERS,
|
|
||||||
PREPARE_ARM11_FOR_FIRMLAUNCH,
|
PREPARE_ARM11_FOR_FIRMLAUNCH,
|
||||||
ARM11_READY,
|
ARM11_READY,
|
||||||
} Arm11Operation;
|
} Arm11Operation;
|
||||||
@ -74,4 +73,3 @@ void swapFramebuffers(bool isAlternate);
|
|||||||
void updateBrightness(u32 brightnessIndex);
|
void updateBrightness(u32 brightnessIndex);
|
||||||
void clearScreens(bool isAlternate);
|
void clearScreens(bool isAlternate);
|
||||||
void initScreens(void);
|
void initScreens(void);
|
||||||
void zerofillN3dsAblRegisters(void);
|
|
||||||
|
|||||||
@ -158,44 +158,23 @@ void error(const char *fmt, ...)
|
|||||||
mcuPowerOff();
|
mcuPowerOff();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// CRC-16/MODBUS
|
|
||||||
u16 crc16(const void *data, size_t size, u16 initialValue)
|
u16 crc16(const void *data, size_t size, u16 initialValue)
|
||||||
{
|
{
|
||||||
static const u16 lut[256] = {
|
static u16 lut[256] = {0};
|
||||||
0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
|
static bool lutInitialized = false;
|
||||||
0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
|
|
||||||
0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
|
if (!lutInitialized)
|
||||||
0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
|
{
|
||||||
0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
|
static const u16 poly = 0xA001;
|
||||||
0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
|
for (u32 i = 0; i < 256; i++)
|
||||||
0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
|
{
|
||||||
0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
|
u16 r = i;
|
||||||
0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
|
for (u32 j = 0; j < 8; j++)
|
||||||
0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
|
r = (r >> 1) ^ ((r & 1) != 0 ? poly : 0);
|
||||||
0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
|
lut[i] = r;
|
||||||
0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
|
}
|
||||||
0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
|
lutInitialized = true;
|
||||||
0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
|
}
|
||||||
0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
|
|
||||||
0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
|
|
||||||
0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
|
|
||||||
0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
|
|
||||||
0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
|
|
||||||
0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
|
|
||||||
0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
|
|
||||||
0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
|
|
||||||
0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
|
|
||||||
0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
|
|
||||||
0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
|
|
||||||
0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
|
|
||||||
0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
|
|
||||||
0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
|
|
||||||
0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
|
|
||||||
0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
|
|
||||||
0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
|
|
||||||
0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040,
|
|
||||||
};
|
|
||||||
|
|
||||||
u16 r = initialValue;
|
u16 r = initialValue;
|
||||||
const u8 *data8 = (const u8 *)data;
|
const u8 *data8 = (const u8 *)data;
|
||||||
@ -207,40 +186,21 @@ u16 crc16(const void *data, size_t size, u16 initialValue)
|
|||||||
|
|
||||||
u32 crc32(const void *data, size_t size, u32 initialValue)
|
u32 crc32(const void *data, size_t size, u32 initialValue)
|
||||||
{
|
{
|
||||||
static const u32 lut[256] = {
|
static u32 lut[256] = {0};
|
||||||
0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,
|
static bool lutInitialized = false;
|
||||||
0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
|
|
||||||
0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,
|
if (!lutInitialized)
|
||||||
0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
|
{
|
||||||
0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,
|
static const u32 poly = 0xEDB88320;
|
||||||
0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
|
for (u32 i = 0; i < 256; i++)
|
||||||
0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,
|
{
|
||||||
0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
|
u32 r = i;
|
||||||
0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,
|
for (u32 j = 0; j < 8; j++)
|
||||||
0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
|
r = (r >> 1) ^ ((r & 1) != 0 ? poly : 0);
|
||||||
0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,
|
lut[i] = r;
|
||||||
0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
|
}
|
||||||
0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,
|
lutInitialized = true;
|
||||||
0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
|
}
|
||||||
0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,
|
|
||||||
0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
|
|
||||||
0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,
|
|
||||||
0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
|
|
||||||
0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,
|
|
||||||
0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
|
|
||||||
0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
|
|
||||||
0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
|
|
||||||
0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,
|
|
||||||
0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
|
|
||||||
0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,
|
|
||||||
0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
|
|
||||||
0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,
|
|
||||||
0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
|
|
||||||
0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,
|
|
||||||
0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
|
|
||||||
0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,
|
|
||||||
0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
|
|
||||||
};
|
|
||||||
|
|
||||||
u32 r = initialValue;
|
u32 r = initialValue;
|
||||||
const u8 *data8 = (const u8 *)data;
|
const u8 *data8 = (const u8 *)data;
|
||||||
|
|||||||
@ -34,12 +34,6 @@
|
|||||||
|
|
||||||
extern bool isN3DS;
|
extern bool isN3DS;
|
||||||
|
|
||||||
// Note: just switch to [[attribute]] once we use clangd and cmake
|
|
||||||
// vscode-cpptools has (or had?) some issues with C23 support
|
|
||||||
#if __GNUC__ >= 15
|
|
||||||
// Required by GCC 15+ but ignored (with warning) before
|
|
||||||
__attribute__((nonstring))
|
|
||||||
#endif
|
|
||||||
static const char serviceList[34][8] =
|
static const char serviceList[34][8] =
|
||||||
{
|
{
|
||||||
"APT:U",
|
"APT:U",
|
||||||
|
|||||||
@ -148,7 +148,7 @@ static u32 findFunctionStart(u8 *code, u32 pos)
|
|||||||
return 0xFFFFFFFF;
|
return 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool findLayeredFsSymbols(u8 *code, u32 size, u32 *fsMountArchive, u32 *fsRegisterArchive, u32 *fsTryOpenFile, u32 *fsOpenFileDirectly, u32 *fsUnMountArchive)
|
static inline bool findLayeredFsSymbols(u8 *code, u32 size, u32 *fsMountArchive, u32 *fsRegisterArchive, u32 *fsTryOpenFile, u32 *fsOpenFileDirectly)
|
||||||
{
|
{
|
||||||
u32 found = 0,
|
u32 found = 0,
|
||||||
*temp = NULL;
|
*temp = NULL;
|
||||||
@ -165,12 +165,6 @@ static inline bool findLayeredFsSymbols(u8 *code, u32 size, u32 *fsMountArchive,
|
|||||||
case 0xE24DD028:
|
case 0xE24DD028:
|
||||||
if(addr <= size - 16 && *fsMountArchive == 0xFFFFFFFF && addr32[1] == 0xE1A04000 && addr32[2] == 0xE59F60A8 && addr32[3] == 0xE3A0C001) temp = fsMountArchive;
|
if(addr <= size - 16 && *fsMountArchive == 0xFFFFFFFF && addr32[1] == 0xE1A04000 && addr32[2] == 0xE59F60A8 && addr32[3] == 0xE3A0C001) temp = fsMountArchive;
|
||||||
break;
|
break;
|
||||||
case 0xE2844001:
|
|
||||||
if(addr <= size - 12 && *fsUnMountArchive == 0xFFFFFFFF && addr32[1] == 0xE3540020 && addr32[2] == 0x3AFFFFF0) temp = fsUnMountArchive;
|
|
||||||
break;
|
|
||||||
case 0xE353003A:
|
|
||||||
if(addr <= size - 12 && *fsUnMountArchive == 0xFFFFFFFF && (addr32[1] & 0xFFFFFF0F) == 0x0A000009 && (addr32[2] & 0xFFFF0FF0) == 0xE1A00400) temp = fsUnMountArchive;
|
|
||||||
break;
|
|
||||||
case 0xE3500008:
|
case 0xE3500008:
|
||||||
if(addr <= size - 12 && *fsRegisterArchive == 0xFFFFFFFF && (addr32[1] & 0xFFF00FF0) == 0xE1800400 && (addr32[2] & 0xFFF00FF0) == 0xE1800FC0) temp = fsRegisterArchive;
|
if(addr <= size - 12 && *fsRegisterArchive == 0xFFFFFFFF && (addr32[1] & 0xFFF00FF0) == 0xE1800400 && (addr32[2] & 0xFFF00FF0) == 0xE1800FC0) temp = fsRegisterArchive;
|
||||||
break;
|
break;
|
||||||
@ -189,14 +183,14 @@ static inline bool findLayeredFsSymbols(u8 *code, u32 size, u32 *fsMountArchive,
|
|||||||
if(*temp != 0xFFFFFFFF)
|
if(*temp != 0xFFFFFFFF)
|
||||||
{
|
{
|
||||||
found++;
|
found++;
|
||||||
if(found == 5) break;
|
if(found == 4) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
temp = NULL;
|
temp = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return found == 5;
|
return found == 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool findLayeredFsPayloadOffset(u8 *code, u32 size, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress, u32 *payloadOffset, u32 *pathOffset, u32 *pathAddress)
|
static inline bool findLayeredFsPayloadOffset(u8 *code, u32 size, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress, u32 *payloadOffset, u32 *pathOffset, u32 *pathAddress)
|
||||||
@ -484,7 +478,7 @@ static inline bool loadTitleLocaleConfig(u64 progId, u8 *mask, u8 *regionId, u8
|
|||||||
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 3) goto exit;
|
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 3) goto exit;
|
||||||
if(fileSize >= 12) fileSize = 12;
|
if(fileSize >= 12) fileSize = 12;
|
||||||
|
|
||||||
char buf[12+1] = "------------";
|
char buf[12] = "------------";
|
||||||
u64 total;
|
u64 total;
|
||||||
|
|
||||||
if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) goto exit;
|
if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) goto exit;
|
||||||
@ -575,7 +569,6 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize,
|
|||||||
if(!archiveId) return true;
|
if(!archiveId) return true;
|
||||||
|
|
||||||
u32 fsMountArchive = 0xFFFFFFFF,
|
u32 fsMountArchive = 0xFFFFFFFF,
|
||||||
fsUnMountArchive = 0xFFFFFFFF,
|
|
||||||
fsRegisterArchive = 0xFFFFFFFF,
|
fsRegisterArchive = 0xFFFFFFFF,
|
||||||
fsTryOpenFile = 0xFFFFFFFF,
|
fsTryOpenFile = 0xFFFFFFFF,
|
||||||
fsOpenFileDirectly = 0xFFFFFFFF,
|
fsOpenFileDirectly = 0xFFFFFFFF,
|
||||||
@ -583,7 +576,7 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize,
|
|||||||
pathOffset = 0,
|
pathOffset = 0,
|
||||||
pathAddress = 0xDEADCAFE;
|
pathAddress = 0xDEADCAFE;
|
||||||
|
|
||||||
if(!findLayeredFsSymbols(code, textSize, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly, &fsUnMountArchive) ||
|
if(!findLayeredFsSymbols(code, textSize, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly) ||
|
||||||
!findLayeredFsPayloadOffset(code, textSize, roSize, dataSize, roAddress, dataAddress, &payloadOffset, &pathOffset, &pathAddress)) return false;
|
!findLayeredFsPayloadOffset(code, textSize, roSize, dataSize, roAddress, dataAddress, &payloadOffset, &pathOffset, &pathAddress)) return false;
|
||||||
|
|
||||||
static const char *updateRomFsMounts[] = { "ro2:",
|
static const char *updateRomFsMounts[] = { "ro2:",
|
||||||
@ -631,9 +624,8 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize,
|
|||||||
romfsRedirPatchSubstituted2 = *(u32 *)(code + fsTryOpenFile);
|
romfsRedirPatchSubstituted2 = *(u32 *)(code + fsTryOpenFile);
|
||||||
romfsRedirPatchHook2 = MAKE_BRANCH(payloadOffset + (u32)&romfsRedirPatchHook2 - (u32)romfsRedirPatch, fsTryOpenFile + 4);
|
romfsRedirPatchHook2 = MAKE_BRANCH(payloadOffset + (u32)&romfsRedirPatchHook2 - (u32)romfsRedirPatch, fsTryOpenFile + 4);
|
||||||
romfsRedirPatchCustomPath = pathAddress;
|
romfsRedirPatchCustomPath = pathAddress;
|
||||||
romfsRedirPatchFsMountArchive = MAKE_BRANCH_LINK(payloadOffset + (u32)&romfsRedirPatchFsMountArchive - (u32)romfsRedirPatch, fsMountArchive);
|
romfsRedirPatchFsMountArchive = 0x100000 + fsMountArchive;
|
||||||
romfsRedirPatchFsUnMountArchive = MAKE_BRANCH_LINK(payloadOffset + (u32)&romfsRedirPatchFsUnMountArchive - (u32)romfsRedirPatch, fsUnMountArchive);
|
romfsRedirPatchFsRegisterArchive = 0x100000 + fsRegisterArchive;
|
||||||
romfsRedirPatchFsRegisterArchive = MAKE_BRANCH_LINK(payloadOffset + (u32)&romfsRedirPatchFsRegisterArchive - (u32)romfsRedirPatch, fsRegisterArchive);
|
|
||||||
romfsRedirPatchArchiveId = archiveId;
|
romfsRedirPatchArchiveId = archiveId;
|
||||||
memcpy(&romfsRedirPatchUpdateRomFsMount, updateRomFsMount, 4);
|
memcpy(&romfsRedirPatchUpdateRomFsMount, updateRomFsMount, 4);
|
||||||
|
|
||||||
@ -734,9 +726,8 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
|
|||||||
progId == 0x0004001000022000LL || //EUR MSET
|
progId == 0x0004001000022000LL || //EUR MSET
|
||||||
progId == 0x0004001000026000LL || //CHN MSET
|
progId == 0x0004001000026000LL || //CHN MSET
|
||||||
progId == 0x0004001000027000LL || //KOR MSET
|
progId == 0x0004001000027000LL || //KOR MSET
|
||||||
progId == 0x0004001000028000LL)) //TWN MSET
|
progId == 0x0004001000028000LL) //TWN MSET
|
||||||
{
|
&& CONFIG(PATCHVERSTRING))
|
||||||
if (CONFIG(PATCHVERSTRING))
|
|
||||||
{
|
{
|
||||||
static const u16 pattern[] = u"Ve";
|
static const u16 pattern[] = u"Ve";
|
||||||
const u16 *patch;
|
const u16 *patch;
|
||||||
@ -764,37 +755,6 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
|
|||||||
)) goto error;
|
)) goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow date picker to select year up to 2099, not just 2050.
|
|
||||||
// NNID user's year-of-birth seems to have a similar restriction,
|
|
||||||
// I'm not removing that as long as any NNID stuff is still active.
|
|
||||||
|
|
||||||
// Patch date picker check on entry (date load):
|
|
||||||
// Look for:
|
|
||||||
// 32 00 5x E3 CMP Rx, #0x32
|
|
||||||
// ...
|
|
||||||
// 32 x0 A0 C3 MOVGT Rx, #0x32
|
|
||||||
u32 *off = (u32 *)code;
|
|
||||||
for (; (u8 *)off < code + textSize && ((off[0] & 0xFFF0FFFF) != 0xE3500032 || (off[2] & 0xFFFF0FFF) != 0xC3A00032); off++)
|
|
||||||
{
|
|
||||||
if (((off[0] >> 16) & 0xF) != ((off[2] >> 12) & 0xF)) // ensure same register used
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((u8 *)off >= code + textSize) goto error;
|
|
||||||
off[0] = (off[0] & ~0xFF) | 99;
|
|
||||||
off[2] = (off[2] & ~0xFF) | 99;
|
|
||||||
|
|
||||||
// Patch date picker actions:
|
|
||||||
// Look for:
|
|
||||||
// 01 00 80 E2 ADD R0, R0, #1
|
|
||||||
// 32 00 50 E3 CMP R0, #0x32
|
|
||||||
off = (u32 *)code;
|
|
||||||
for (; (u8 *)off < code + textSize && (off[0] != 0xE2800001 || off[1] != 0xE3500032); off++);
|
|
||||||
if ((u8 *)off >= code + textSize) goto error;
|
|
||||||
|
|
||||||
off[1] = (off[1] & ~0xFF) | 99; // patch increment wrap-around compare instruction
|
|
||||||
off[9] = (off[9] & ~0xFF) | 99; // patch decrement wrap-around conditional move instruction
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(progId == 0x0004013000008002LL) //NS
|
else if(progId == 0x0004013000008002LL) //NS
|
||||||
{
|
{
|
||||||
if(progVer > 4)
|
if(progVer > 4)
|
||||||
|
|||||||
@ -10,7 +10,6 @@ extern u32 romfsRedirPatchSubstituted2, romfsRedirPatchHook2;
|
|||||||
|
|
||||||
extern u32 romfsRedirPatchArchiveName;
|
extern u32 romfsRedirPatchArchiveName;
|
||||||
extern u32 romfsRedirPatchFsMountArchive;
|
extern u32 romfsRedirPatchFsMountArchive;
|
||||||
extern u32 romfsRedirPatchFsUnMountArchive;
|
|
||||||
extern u32 romfsRedirPatchFsRegisterArchive;
|
extern u32 romfsRedirPatchFsRegisterArchive;
|
||||||
extern u32 romfsRedirPatchArchiveId;
|
extern u32 romfsRedirPatchArchiveId;
|
||||||
extern u32 romfsRedirPatchRomFsMount;
|
extern u32 romfsRedirPatchRomFsMount;
|
||||||
|
|||||||
@ -30,23 +30,17 @@ romfsRedirPatch:
|
|||||||
cmp r3, #3
|
cmp r3, #3
|
||||||
bne romfsRedirPatchSubstituted1
|
bne romfsRedirPatchSubstituted1
|
||||||
stmfd sp!, {r0-r4, lr}
|
stmfd sp!, {r0-r4, lr}
|
||||||
adr r0, romfsRedirPatchArchiveName
|
|
||||||
.global romfsRedirPatchFsUnMountArchive
|
|
||||||
romfsRedirPatchFsUnMountArchive:
|
|
||||||
.word 0xdead0004
|
|
||||||
sub sp, sp, #4
|
sub sp, sp, #4
|
||||||
ldr r1, romfsRedirPatchArchiveId
|
ldr r1, romfsRedirPatchArchiveId
|
||||||
mov r0, sp
|
mov r0, sp
|
||||||
.global romfsRedirPatchFsMountArchive
|
ldr r4, romfsRedirPatchFsMountArchive
|
||||||
romfsRedirPatchFsMountArchive:
|
blx r4
|
||||||
.word 0xdead0005
|
|
||||||
mov r3, #0
|
mov r3, #0
|
||||||
mov r2, #0
|
mov r2, #0
|
||||||
ldr r1, [sp]
|
ldr r1, [sp]
|
||||||
adr r0, romfsRedirPatchArchiveName
|
adr r0, romfsRedirPatchArchiveName
|
||||||
.global romfsRedirPatchFsRegisterArchive
|
ldr r4, romfsRedirPatchFsRegisterArchive
|
||||||
romfsRedirPatchFsRegisterArchive:
|
blx r4
|
||||||
.word 0xdead0006
|
|
||||||
add sp, sp, #4
|
add sp, sp, #4
|
||||||
ldmfd sp!, {r0-r4, lr}
|
ldmfd sp!, {r0-r4, lr}
|
||||||
b romfsRedirPatchSubstituted1
|
b romfsRedirPatchSubstituted1
|
||||||
@ -114,16 +108,20 @@ romfsRedirPatch:
|
|||||||
.balign 4
|
.balign 4
|
||||||
|
|
||||||
.global romfsRedirPatchArchiveName
|
.global romfsRedirPatchArchiveName
|
||||||
|
.global romfsRedirPatchFsMountArchive
|
||||||
|
.global romfsRedirPatchFsRegisterArchive
|
||||||
.global romfsRedirPatchArchiveId
|
.global romfsRedirPatchArchiveId
|
||||||
.global romfsRedirPatchRomFsMount
|
.global romfsRedirPatchRomFsMount
|
||||||
.global romfsRedirPatchUpdateRomFsMount
|
.global romfsRedirPatchUpdateRomFsMount
|
||||||
.global romfsRedirPatchCustomPath
|
.global romfsRedirPatchCustomPath
|
||||||
|
|
||||||
romfsRedirPatchArchiveName : .ascii "lf:\0"
|
romfsRedirPatchArchiveName : .ascii "lf:\0"
|
||||||
|
romfsRedirPatchFsMountArchive : .word 0xdead0005
|
||||||
|
romfsRedirPatchFsRegisterArchive : .word 0xdead0006
|
||||||
romfsRedirPatchArchiveId : .word 0xdead0007
|
romfsRedirPatchArchiveId : .word 0xdead0007
|
||||||
romfsRedirPatchRomFsMount : .ascii "rom:"
|
romfsRedirPatchRomFsMount : .ascii "rom:"
|
||||||
romfsRedirPatchUpdateRomFsMount : .word 0xdead0008
|
romfsRedirPatchUpdateRomFsMount : .word 0xdead0008
|
||||||
romfsRedirPatchCustomPath : .word 0xdead0009
|
romfsRedirPatchCustomPath : .word 0xdead0004
|
||||||
|
|
||||||
_romfsRedirPatchEnd:
|
_romfsRedirPatchEnd:
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -62,7 +62,7 @@ typedef struct MenuItem {
|
|||||||
typedef struct Menu {
|
typedef struct Menu {
|
||||||
const char *title;
|
const char *title;
|
||||||
|
|
||||||
MenuItem items[25];
|
MenuItem items[24];
|
||||||
} Menu;
|
} Menu;
|
||||||
|
|
||||||
extern u32 menuCombo;
|
extern u32 menuCombo;
|
||||||
|
|||||||
@ -36,7 +36,6 @@ void RosalinaMenu_TakeScreenshot(void);
|
|||||||
void RosalinaMenu_ShowCredits(void);
|
void RosalinaMenu_ShowCredits(void);
|
||||||
void RosalinaMenu_ProcessList(void);
|
void RosalinaMenu_ProcessList(void);
|
||||||
void RosalinaMenu_SaveSettings(void);
|
void RosalinaMenu_SaveSettings(void);
|
||||||
void RosalinaMenu_ReturnToHomeMenu(void);
|
|
||||||
void RosalinaMenu_Cheats(void);
|
void RosalinaMenu_Cheats(void);
|
||||||
|
|
||||||
void RosalinaMenu_PowerOffOrReboot(void);
|
void RosalinaMenu_PowerOffOrReboot(void);
|
||||||
|
|||||||
@ -56,12 +56,10 @@ typedef struct
|
|||||||
s32* plgldrEvent; ///< Used for synchronization
|
s32* plgldrEvent; ///< Used for synchronization
|
||||||
s32* plgldrReply; ///< Used for synchronization
|
s32* plgldrReply; ///< Used for synchronization
|
||||||
u8 notifyHomeEvent;
|
u8 notifyHomeEvent;
|
||||||
u8 padding[7];
|
u8 padding[3];
|
||||||
u64 waitForReplyTimeout;
|
u32 reserved[23];
|
||||||
u32 reserved[20];
|
|
||||||
u32 config[32];
|
u32 config[32];
|
||||||
} PluginHeader;
|
} PluginHeader;
|
||||||
_Static_assert(sizeof(PluginHeader) == 0x100, "Invalid PluginHeader size");
|
|
||||||
|
|
||||||
typedef void (*OnPlgLdrEventCb_t)(s32 eventType);
|
typedef void (*OnPlgLdrEventCb_t)(s32 eventType);
|
||||||
|
|
||||||
|
|||||||
@ -30,7 +30,6 @@
|
|||||||
#include <3ds/srv.h>
|
#include <3ds/srv.h>
|
||||||
#include <3ds/result.h>
|
#include <3ds/result.h>
|
||||||
#include <3ds/ipc.h>
|
#include <3ds/ipc.h>
|
||||||
#include <assert.h>
|
|
||||||
#include "csvc.h"
|
#include "csvc.h"
|
||||||
#include "luma_shared_config.h"
|
#include "luma_shared_config.h"
|
||||||
|
|
||||||
|
|||||||
@ -268,18 +268,14 @@ static inline void Draw_WriteUnaligned(u8 *dst, u32 tmp, u32 size)
|
|||||||
void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth)
|
void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth)
|
||||||
{
|
{
|
||||||
static const u8 bmpHeaderTemplate[54] = {
|
static const u8 bmpHeaderTemplate[54] = {
|
||||||
// BITMAPFILEHEADER
|
0x42, 0x4D, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
|
||||||
0x42, 0x4D, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x40 /* data offset */, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00,
|
||||||
// BITMAPINFOHEADER
|
|
||||||
0x28, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x01, 0x00, 0x18, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
memcpy(dst, bmpHeaderTemplate, 54);
|
memcpy(dst, bmpHeaderTemplate, 54);
|
||||||
memset(dst + 54, 0, 64 - 54);
|
Draw_WriteUnaligned(dst + 2, 54 + 3 * width * heigth, 4);
|
||||||
Draw_WriteUnaligned(dst + 2, 64 + 3 * width * heigth, 4);
|
|
||||||
Draw_WriteUnaligned(dst + 0x12, width, 4);
|
Draw_WriteUnaligned(dst + 0x12, width, 4);
|
||||||
Draw_WriteUnaligned(dst + 0x16, heigth, 4);
|
Draw_WriteUnaligned(dst + 0x16, heigth, 4);
|
||||||
Draw_WriteUnaligned(dst + 0x22, 3 * width * heigth, 4);
|
Draw_WriteUnaligned(dst + 0x22, 3 * width * heigth, 4);
|
||||||
|
|||||||
@ -204,7 +204,7 @@ void LumaConfig_RequestSaveSettings(void) {
|
|||||||
|
|
||||||
Result LumaConfig_SaveSettings(void)
|
Result LumaConfig_SaveSettings(void)
|
||||||
{
|
{
|
||||||
char inibuf[0x2000 + 0x400]; // eyeballed. TODO use #embed
|
char inibuf[0x2000];
|
||||||
|
|
||||||
Result res;
|
Result res;
|
||||||
|
|
||||||
@ -259,12 +259,6 @@ Result LumaConfig_SaveSettings(void)
|
|||||||
configData.autobootCtrAppmemtype = autobootCtrAppmemtype;
|
configData.autobootCtrAppmemtype = autobootCtrAppmemtype;
|
||||||
|
|
||||||
size_t n = LumaConfig_SaveLumaIniConfigToStr(inibuf, &configData);
|
size_t n = LumaConfig_SaveLumaIniConfigToStr(inibuf, &configData);
|
||||||
|
|
||||||
// FIXME: this is UB we should port snprintf sometime (as well as fix other tech debt in Rosalina)
|
|
||||||
if (n + 1 >= sizeof(inibuf)) {
|
|
||||||
__builtin_trap();
|
|
||||||
}
|
|
||||||
|
|
||||||
FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
|
FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
res = IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, "/luma/config.ini"), FS_OPEN_CREATE | FS_OPEN_WRITE);
|
res = IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, "/luma/config.ini"), FS_OPEN_CREATE | FS_OPEN_WRITE);
|
||||||
|
|||||||
@ -104,13 +104,8 @@ u32 getMinLuminancePreset(void)
|
|||||||
|
|
||||||
u32 getMaxLuminancePreset(void)
|
u32 getMaxLuminancePreset(void)
|
||||||
{
|
{
|
||||||
// Unlike SetLuminanceLevel, SetLuminance doesn't
|
|
||||||
// check if preset <= 5, and actually allows the lumiance
|
|
||||||
// levels provisioned for the "brightness boost mode" (brighter
|
|
||||||
// when adapter is plugged in), even when the feature is disabled
|
|
||||||
// (it is disabled for anything but the OG model, iirc)
|
|
||||||
readCalibration();
|
readCalibration();
|
||||||
return s_blPwmData.luminanceLevels[6];
|
return s_blPwmData.luminanceLevels[s_blPwmData.numLevels - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 getCurrentLuminance(bool top)
|
u32 getCurrentLuminance(bool top)
|
||||||
@ -119,8 +114,7 @@ u32 getCurrentLuminance(bool top)
|
|||||||
|
|
||||||
readCalibration();
|
readCalibration();
|
||||||
|
|
||||||
bool is3d = (REG32(0x10202000 + 0x000) & 1) != 0;
|
const float *coeffs = s_blPwmData.coeffs[top ? (isN3DS ? 2 : 1) : 0];
|
||||||
const float *coeffs = s_blPwmData.coeffs[top ? (is3d ? 2 : 1) : 0];
|
|
||||||
u32 brightness = REG32(regbase + 0x40);
|
u32 brightness = REG32(regbase + 0x40);
|
||||||
float ratio = getPwmRatio(s_blPwmData.brightnessMax, REG32(regbase + 0x44));
|
float ratio = getPwmRatio(s_blPwmData.brightnessMax, REG32(regbase + 0x44));
|
||||||
|
|
||||||
|
|||||||
@ -55,7 +55,6 @@ Menu rosalinaMenu = {
|
|||||||
{ "System configuration...", MENU, .menu = &sysconfigMenu },
|
{ "System configuration...", MENU, .menu = &sysconfigMenu },
|
||||||
{ "Miscellaneous options...", MENU, .menu = &miscellaneousMenu },
|
{ "Miscellaneous options...", MENU, .menu = &miscellaneousMenu },
|
||||||
{ "Save settings", METHOD, .method = &RosalinaMenu_SaveSettings },
|
{ "Save settings", METHOD, .method = &RosalinaMenu_SaveSettings },
|
||||||
{ "Return To Home Menu", METHOD, .method = &RosalinaMenu_ReturnToHomeMenu },
|
|
||||||
{ "Power off / reboot", METHOD, .method = &RosalinaMenu_PowerOffOrReboot },
|
{ "Power off / reboot", METHOD, .method = &RosalinaMenu_PowerOffOrReboot },
|
||||||
{ "System info", METHOD, .method = &RosalinaMenu_ShowSystemInfo },
|
{ "System info", METHOD, .method = &RosalinaMenu_ShowSystemInfo },
|
||||||
{ "Credits", METHOD, .method = &RosalinaMenu_ShowCredits },
|
{ "Credits", METHOD, .method = &RosalinaMenu_ShowCredits },
|
||||||
@ -228,7 +227,7 @@ void RosalinaMenu_ShowCredits(void)
|
|||||||
Draw_Lock();
|
Draw_Lock();
|
||||||
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina -- Luma3DS credits");
|
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina -- Luma3DS credits");
|
||||||
|
|
||||||
u32 posY = Draw_DrawString(10, 30, COLOR_WHITE, "Luma3DS (c) 2016-2025 AuroraWright, TuxSH") + SPACING_Y;
|
u32 posY = Draw_DrawString(10, 30, COLOR_WHITE, "Luma3DS (c) 2016-2024 AuroraWright, TuxSH") + SPACING_Y;
|
||||||
|
|
||||||
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "3DSX loading code by fincs");
|
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "3DSX loading code by fincs");
|
||||||
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "Networking code & basic GDB functionality by Stary");
|
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "Networking code & basic GDB functionality by Stary");
|
||||||
@ -274,8 +273,7 @@ static Result RosalinaMenu_WriteScreenshot(IFile *file, u32 width, bool top, boo
|
|||||||
|
|
||||||
u8 *buf = framebufferCache;
|
u8 *buf = framebufferCache;
|
||||||
Draw_CreateBitmapHeader(framebufferCache, width, numLinesScaled);
|
Draw_CreateBitmapHeader(framebufferCache, width, numLinesScaled);
|
||||||
const u32 headerSize = 0x40;
|
buf += 54;
|
||||||
buf += headerSize;
|
|
||||||
|
|
||||||
u32 y = 0;
|
u32 y = 0;
|
||||||
// Our buffer might be smaller than the size of the screenshot...
|
// Our buffer might be smaller than the size of the screenshot...
|
||||||
@ -289,7 +287,7 @@ static Result RosalinaMenu_WriteScreenshot(IFile *file, u32 width, bool top, boo
|
|||||||
|
|
||||||
s64 t1 = svcGetSystemTick();
|
s64 t1 = svcGetSystemTick();
|
||||||
timeSpentConvertingScreenshot += t1 - t0;
|
timeSpentConvertingScreenshot += t1 - t0;
|
||||||
TRY(IFile_Write(file, &total, framebufferCache, (y == 0 ? headerSize : 0) + lineSize * nlines * scaleFactorY, 0)); // don't forget to write the header
|
TRY(IFile_Write(file, &total, framebufferCache, (y == 0 ? 54 : 0) + lineSize * nlines * scaleFactorY, 0)); // don't forget to write the header
|
||||||
timeSpentWritingScreenshot += svcGetSystemTick() - t1;
|
timeSpentWritingScreenshot += svcGetSystemTick() - t1;
|
||||||
|
|
||||||
y += nlines;
|
y += nlines;
|
||||||
@ -302,35 +300,6 @@ static Result RosalinaMenu_WriteScreenshot(IFile *file, u32 width, bool top, boo
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RosalinaMenu_ReturnToHomeMenu(void)
|
|
||||||
{
|
|
||||||
Draw_Lock();
|
|
||||||
Draw_ClearFramebuffer();
|
|
||||||
Draw_FlushFramebuffer();
|
|
||||||
Draw_Unlock();
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
Draw_Lock();
|
|
||||||
Draw_DrawString(10, 10, COLOR_TITLE, "Return to Home Menu");
|
|
||||||
Draw_DrawString(10, 30, COLOR_WHITE, "Press A to confirm.\nPress B to go back.");
|
|
||||||
Draw_FlushFramebuffer();
|
|
||||||
Draw_Unlock();
|
|
||||||
|
|
||||||
u32 pressed = waitInputWithTimeout(1000);
|
|
||||||
|
|
||||||
if(pressed & KEY_A)
|
|
||||||
{
|
|
||||||
menuLeave();
|
|
||||||
srvPublishToSubscriber(0x204, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if(pressed & KEY_B)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while(!menuShouldExit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RosalinaMenu_TakeScreenshot(void)
|
void RosalinaMenu_TakeScreenshot(void)
|
||||||
{
|
{
|
||||||
IFile file = {0};
|
IFile file = {0};
|
||||||
|
|||||||
@ -367,6 +367,11 @@ void MiscellaneousMenu_UpdateTimeDateNtp(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Draw_Lock();
|
||||||
|
Draw_ClearFramebuffer();
|
||||||
|
Draw_FlushFramebuffer();
|
||||||
|
Draw_Unlock();
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Draw_Lock();
|
Draw_Lock();
|
||||||
|
|||||||
@ -420,30 +420,8 @@ static Result SysConfigMenu_ApplyVolumeOverride(void)
|
|||||||
s8 i2s2Volume;
|
s8 i2s2Volume;
|
||||||
if (currVolumeSliderOverride >= 0)
|
if (currVolumeSliderOverride >= 0)
|
||||||
{
|
{
|
||||||
// Considering I found this table inside MCU fw bin (at around offset 0x1200 in the raw bin):
|
i2s1Volume = -128 + (((float)currVolumeSliderOverride/100.f) * 108);
|
||||||
// 127, 126, 125, ... 56
|
i2s2Volume = i2s1Volume;
|
||||||
// which corresponds to round(127 - 71 * (i/63)) modulo some rounding error, it is certain
|
|
||||||
// that the MCU writes to "Page 0/Register 117: VOL/MICDET-Pin Gain" using linear interpolation
|
|
||||||
// to map the slider position (0..63) to the raw gain values, using 127 ("reserved") as "mute".
|
|
||||||
// Indeed, the value used in all calibration data for shutter volume is -10 dB, which maps to 56.
|
|
||||||
|
|
||||||
// However, if you look at the definition of reg 0,117 closely, you will notice that the mapping
|
|
||||||
// to the 7-bit value is piecewise, with half the resolution (double the slope) for values mapping
|
|
||||||
// to -28 dB or lower, which means that the slider increases volume twice as fast below 50% position.
|
|
||||||
|
|
||||||
// LERP like MCU does, round to nearest integer
|
|
||||||
u8 rawPinGain = 127 - (71 * currVolumeSliderOverride + 50) / 100;
|
|
||||||
s8 volume;
|
|
||||||
|
|
||||||
if (rawPinGain <= 90)
|
|
||||||
volume = 36 - rawPinGain;
|
|
||||||
else if (rawPinGain >= 91 && rawPinGain <= 126)
|
|
||||||
volume = 126 - 2 * rawPinGain;
|
|
||||||
else
|
|
||||||
volume = -128; // mute
|
|
||||||
|
|
||||||
i2s1Volume = volume;
|
|
||||||
i2s2Volume = volume;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -582,7 +560,7 @@ void SysConfigMenu_ChangeScreenBrightness(void)
|
|||||||
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press A to start, B to exit.\n\n");
|
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press A to start, B to exit.\n\n");
|
||||||
|
|
||||||
posY = Draw_DrawString(10, posY, COLOR_RED, "WARNING: \n");
|
posY = Draw_DrawString(10, posY, COLOR_RED, "WARNING: \n");
|
||||||
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * value will be limited by calibration.\n");
|
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * value will be limited by the presets.\n");
|
||||||
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * bottom framebuffer will be restored until\nyou exit.");
|
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * bottom framebuffer will be restored until\nyou exit.");
|
||||||
Draw_FlushFramebuffer();
|
Draw_FlushFramebuffer();
|
||||||
Draw_Unlock();
|
Draw_Unlock();
|
||||||
|
|||||||
@ -270,7 +270,6 @@ bool TryToLoadPlugin(Handle process, bool isHomebrew)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pluginHeader->version = header->version;
|
pluginHeader->version = header->version;
|
||||||
pluginHeader->waitForReplyTimeout = 10000000000ULL;
|
|
||||||
// Code size must be page aligned
|
// Code size must be page aligned
|
||||||
exeHdr = &header->executable;
|
exeHdr = &header->executable;
|
||||||
pluginHeader->exeSize = (sizeof(PluginHeader) + exeHdr->codeSize + exeHdr->rodataSize + exeHdr->dataSize + exeHdr->bssSize + 0x1000) & ~0xFFF;
|
pluginHeader->exeSize = (sizeof(PluginHeader) + exeHdr->codeSize + exeHdr->rodataSize + exeHdr->dataSize + exeHdr->bssSize + 0x1000) & ~0xFFF;
|
||||||
|
|||||||
@ -113,7 +113,7 @@ Result PLGLDR__SetPluginLoadParameters(PluginLoadParameters *parameters)
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
void Flash(u32 color);
|
||||||
Result PLGLDR__DisplayMenu(PluginMenu *menu)
|
Result PLGLDR__DisplayMenu(PluginMenu *menu)
|
||||||
{
|
{
|
||||||
Result res = 0;
|
Result res = 0;
|
||||||
@ -136,6 +136,7 @@ Result PLGLDR__DisplayMenu(PluginMenu *menu)
|
|||||||
{
|
{
|
||||||
res = cmdbuf[1];
|
res = cmdbuf[1];
|
||||||
}
|
}
|
||||||
|
else Flash(0xFF0000);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,9 @@ static const char *g_title = "Plugin loader";
|
|||||||
PluginLoaderContext PluginLoaderCtx;
|
PluginLoaderContext PluginLoaderCtx;
|
||||||
extern u32 g_blockMenuOpen;
|
extern u32 g_blockMenuOpen;
|
||||||
|
|
||||||
|
void IR__Patch(void);
|
||||||
|
void IR__Unpatch(void);
|
||||||
|
|
||||||
void PluginLoader__Init(void)
|
void PluginLoader__Init(void)
|
||||||
{
|
{
|
||||||
PluginLoaderContext *ctx = &PluginLoaderCtx;
|
PluginLoaderContext *ctx = &PluginLoaderCtx;
|
||||||
@ -133,6 +136,10 @@ Result PluginLoader__SetMode3AppMode(bool enable)
|
|||||||
}
|
}
|
||||||
static void j_PluginLoader__SetMode3AppMode(void* arg) {(void)arg; PluginLoader__SetMode3AppMode(false);}
|
static void j_PluginLoader__SetMode3AppMode(void* arg) {(void)arg; PluginLoader__SetMode3AppMode(false);}
|
||||||
|
|
||||||
|
void CheckMemory(void);
|
||||||
|
|
||||||
|
void PLG__NotifyEvent(PLG_Event event, bool signal);
|
||||||
|
|
||||||
void PluginLoader__HandleCommands(void *_ctx)
|
void PluginLoader__HandleCommands(void *_ctx)
|
||||||
{
|
{
|
||||||
(void)_ctx;
|
(void)_ctx;
|
||||||
@ -169,6 +176,8 @@ void PluginLoader__HandleCommands(void *_ctx)
|
|||||||
}
|
}
|
||||||
REG32(0x10202204) = 0;
|
REG32(0x10202204) = 0;
|
||||||
}
|
}
|
||||||
|
//if (!ctx->userLoadParameters.noIRPatch)
|
||||||
|
// IR__Patch();
|
||||||
PLG__SetConfigMemoryStatus(PLG_CFG_RUNNING);
|
PLG__SetConfigMemoryStatus(PLG_CFG_RUNNING);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -507,7 +516,7 @@ void PLG__WaitForReply(void)
|
|||||||
{
|
{
|
||||||
if (PluginLoaderCtx.eventsSelfManaged) return;
|
if (PluginLoaderCtx.eventsSelfManaged) return;
|
||||||
__strex__(PluginLoaderCtx.plgReplyPA, PLG_WAIT);
|
__strex__(PluginLoaderCtx.plgReplyPA, PLG_WAIT);
|
||||||
svcArbitrateAddress(PluginLoaderCtx.arbiter, (u32)PluginLoaderCtx.plgReplyPA, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, PLG_OK, MemoryBlock__GetMappedPluginHeader()->waitForReplyTimeout);
|
svcArbitrateAddress(PluginLoaderCtx.arbiter, (u32)PluginLoaderCtx.plgReplyPA, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, PLG_OK, 10000000000ULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PLG__SetConfigMemoryStatus(u32 status)
|
void PLG__SetConfigMemoryStatus(u32 status)
|
||||||
@ -552,6 +561,8 @@ static void WaitForProcessTerminated(void *arg)
|
|||||||
ctx->isMemPrivate = false;
|
ctx->isMemPrivate = false;
|
||||||
g_blockMenuOpen = 0;
|
g_blockMenuOpen = 0;
|
||||||
MemoryBlock__ResetSwapSettings();
|
MemoryBlock__ResetSwapSettings();
|
||||||
|
//if (!ctx->userLoadParameters.noIRPatch)
|
||||||
|
// IR__Unpatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginLoader__HandleKernelEvent(u32 notifId)
|
void PluginLoader__HandleKernelEvent(u32 notifId)
|
||||||
@ -637,6 +648,7 @@ void PluginLoader__HandleKernelEvent(u32 notifId)
|
|||||||
}
|
}
|
||||||
ctx->pluginIsHome = !ctx->pluginIsHome;
|
ctx->pluginIsHome = !ctx->pluginIsHome;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
srvPublishToSubscriber(0x1002, 0);
|
srvPublishToSubscriber(0x1002, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user