Compare commits

..

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

16 changed files with 105 additions and 269 deletions

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

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

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

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

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

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

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

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

@ -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;
@ -102,7 +105,7 @@ Result PluginLoader__SetMode3AppMode(bool enable)
if (enable) { if (enable) {
ControlApplicationMemoryModeOverrideConfig* mode = (ControlApplicationMemoryModeOverrideConfig*)&cmdbuf[1]; ControlApplicationMemoryModeOverrideConfig* mode = (ControlApplicationMemoryModeOverrideConfig*)&cmdbuf[1];
memset(mode, 0, sizeof(ControlApplicationMemoryModeOverrideConfig)); memset(mode, 0, sizeof(ControlApplicationMemoryModeOverrideConfig));
mode->query = true; mode->query = true;
cmdbuf[0] = IPC_MakeHeader(0x101, 1, 0); // ControlApplicationMemoryModeOverride cmdbuf[0] = IPC_MakeHeader(0x101, 1, 0); // ControlApplicationMemoryModeOverride
@ -127,12 +130,16 @@ Result PluginLoader__SetMode3AppMode(bool enable)
res = cmdbuf[1]; res = cmdbuf[1];
} }
} }
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
@ -231,14 +240,14 @@ void PluginLoader__HandleCommands(void *_ctx)
params->pluginMemoryStrategy = (cmdbuf[1] >> 8) & 0xFF; params->pluginMemoryStrategy = (cmdbuf[1] >> 8) & 0xFF;
params->persistent = (cmdbuf[1] >> 16) & 0x1; params->persistent = (cmdbuf[1] >> 16) & 0x1;
params->lowTitleId = cmdbuf[2]; params->lowTitleId = cmdbuf[2];
strncpy(params->path, (const char *)cmdbuf[4], 255); strncpy(params->path, (const char *)cmdbuf[4], 255);
memcpy(params->config, (void *)cmdbuf[6], 32 * sizeof(u32)); memcpy(params->config, (void *)cmdbuf[6], 32 * sizeof(u32));
if (params->persistent) if (params->persistent)
{ {
IFile file; IFile file;
if (R_SUCCEEDED(IFile_Open(&file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, "/luma/plugins/user_param.bin"), if (R_SUCCEEDED(IFile_Open(&file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, "/luma/plugins/user_param.bin"),
FS_OPEN_CREATE | FS_OPEN_READ | FS_OPEN_WRITE))) { FS_OPEN_CREATE | FS_OPEN_READ | FS_OPEN_WRITE))) {
u64 tempWritten; u64 tempWritten;
u32 magic = PERS_USER_FILE_MAGIC; u32 magic = PERS_USER_FILE_MAGIC;
@ -367,9 +376,9 @@ void PluginLoader__HandleCommands(void *_ctx)
error(cmdbuf, 0xD9001830); error(cmdbuf, 0xD9001830);
break; break;
} }
g_blockMenuOpen = cmdbuf[1]; g_blockMenuOpen = cmdbuf[1];
cmdbuf[0] = IPC_MakeHeader(11, 1, 0); cmdbuf[0] = IPC_MakeHeader(11, 1, 0);
cmdbuf[1] = 0; cmdbuf[1] = 0;
break; break;
@ -433,7 +442,7 @@ void PluginLoader__HandleCommands(void *_ctx)
Reset_3gx_LoadParams(); Reset_3gx_LoadParams();
break; break;
} }
ctx->isExeLoadFunctionset = true; ctx->isExeLoadFunctionset = true;
svcInvalidateEntireInstructionCache(); // Could use the range one svcInvalidateEntireInstructionCache(); // Could use the range one
@ -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)
@ -532,7 +541,7 @@ static void WaitForProcessTerminated(void *arg)
// Wait until all threads of the process have finished (svcWaitSynchronization == 0) or 2.5 seconds have passed. // Wait until all threads of the process have finished (svcWaitSynchronization == 0) or 2.5 seconds have passed.
for (u32 i = 0; svcWaitSynchronization(ctx->target, 0) != 0 && i < 50; i++) svcSleepThread(50000000); // 50ms for (u32 i = 0; svcWaitSynchronization(ctx->target, 0) != 0 && i < 50; i++) svcSleepThread(50000000); // 50ms
// Unmap plugin's memory before closing the process // Unmap plugin's memory before closing the process
if (!ctx->pluginIsSwapped) { if (!ctx->pluginIsSwapped) {
MemoryBlock__UnmountFromProcess(); MemoryBlock__UnmountFromProcess();
@ -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)
@ -632,11 +643,12 @@ void PluginLoader__HandleKernelEvent(u32 notifId)
PLG__NotifyEvent(PLG_HOME_ENTER, false); PLG__NotifyEvent(PLG_HOME_ENTER, false);
// Wait for plugin reply // Wait for plugin reply
PLG__WaitForReply(); PLG__WaitForReply();
} }
PLG__SetConfigMemoryStatus(PLG_CFG_INHOME); PLG__SetConfigMemoryStatus(PLG_CFG_INHOME);
} }
ctx->pluginIsHome = !ctx->pluginIsHome; ctx->pluginIsHome = !ctx->pluginIsHome;
} }
} }
srvPublishToSubscriber(0x1002, 0); srvPublishToSubscriber(0x1002, 0);
} }