Compare commits

..

No commits in common. "master" and "v13.3.1" have entirely different histories.

28 changed files with 3197 additions and 551 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);
} }

View File

@ -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;

View File

@ -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')
@ -448,11 +446,6 @@ static bool backupEssentialFiles(void)
sprintf(pathStart, "backups/%08lX/", deviceID); sprintf(pathStart, "backups/%08lX/", deviceID);
char fullPath[0x80]; 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); sprintf(fullPath, "%sHWCAL0.dat", pathStart);
ok = ok && fileCopy("nand:/ro/sys/HWCAL0.dat", fullPath, false, fileCopyBuffer, sz); ok = ok && fileCopy("nand:/ro/sys/HWCAL0.dat", fullPath, false, fileCopyBuffer, sz);

View File

@ -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,

View File

@ -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;
} }

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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",

View File

@ -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,65 +726,33 @@ 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";
const u16 *patch;
u32 patchSize = 0,
currentNand = BOOTCFG_NAND;
u16 customVerString[19];
loadCustomVerString(customVerString, &patchSize, currentNand);
if(patchSize != 0) patch = customVerString;
else
{ {
static const u16 pattern[] = u"Ve"; patchSize = 8;
const u16 *patch;
u32 patchSize = 0,
currentNand = BOOTCFG_NAND;
u16 customVerString[19]; static const u16 *const verStringNandEmu[] = { u" Emu", u"Emu2", u"Emu3", u"Emu4" };
loadCustomVerString(customVerString, &patchSize, currentNand); patch = currentNand == 0 ? u" Sys" : verStringNandEmu[BOOTCFG_EMUINDEX];
if(patchSize != 0) patch = customVerString;
else
{
patchSize = 8;
static const u16 *const verStringNandEmu[] = { u" Emu", u"Emu2", u"Emu3", u"Emu4" };
patch = currentNand == 0 ? u" Sys" : verStringNandEmu[BOOTCFG_EMUINDEX];
}
//Patch Ver. string
if(!patchMemory(code, textSize,
pattern,
sizeof(pattern) - 2, 0,
patch,
patchSize, 1
)) goto error;
} }
// Allow date picker to select year up to 2099, not just 2050. //Patch Ver. string
// NNID user's year-of-birth seems to have a similar restriction, if(!patchMemory(code, textSize,
// I'm not removing that as long as any NNID stuff is still active. pattern,
sizeof(pattern) - 2, 0,
// Patch date picker check on entry (date load): patch,
// Look for: patchSize, 1
// 32 00 5x E3 CMP Rx, #0x32 )) goto error;
// ...
// 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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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"

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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};

View File

@ -367,6 +367,11 @@ void MiscellaneousMenu_UpdateTimeDateNtp(void)
} }
} }
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_Unlock();
do do
{ {
Draw_Lock(); Draw_Lock();

View File

@ -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();

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
@ -93,7 +96,7 @@ void PluginLoader__UpdateMenu(void)
static ControlApplicationMemoryModeOverrideConfig g_memorymodeoverridebackup = { 0 }; static ControlApplicationMemoryModeOverrideConfig g_memorymodeoverridebackup = { 0 };
Result PluginLoader__SetMode3AppMode(bool enable) Result PluginLoader__SetMode3AppMode(bool enable)
{ {
Handle loaderHandle; Handle loaderHandle;
Result res = srvGetServiceHandle(&loaderHandle, "Loader"); Result res = srvGetServiceHandle(&loaderHandle, "Loader");
if (R_FAILED(res)) return res; if (R_FAILED(res)) return res;
@ -128,11 +131,15 @@ Result PluginLoader__SetMode3AppMode(bool enable)
} }
} }
svcCloseHandle(loaderHandle); svcCloseHandle(loaderHandle);
return res; return res;
} }
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);
} }