From b17eb66d55fe0df891d50bfb493062cb61a76104 Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Wed, 8 Jul 2020 22:08:57 +0100 Subject: [PATCH] rosalina inputredir: Use ir patch from @Nanquitas ; also refactor the code Fixes #1428, #1438 (I think) --- .../rosalina/source/input_redirection.c | 459 ++++++++++-------- 1 file changed, 268 insertions(+), 191 deletions(-) diff --git a/sysmodules/rosalina/source/input_redirection.c b/sysmodules/rosalina/source/input_redirection.c index 631cca4..d329391 100644 --- a/sysmodules/rosalina/source/input_redirection.c +++ b/sysmodules/rosalina/source/input_redirection.c @@ -168,6 +168,246 @@ void inputRedirectionThreadMain(void) void hidCodePatchFunc(void); void irCodePatchFunc(void); +static Result InputRedirection_DoUndoIrPatches(Handle processHandle, bool doPatch) +{ + static u32* hookLoc = NULL; + static u32* syncLoc = NULL; + static u32* cppFlagLoc = NULL; + static u32 origIrSync = 0; + static u32 origCppFlag = 0; + + static bool patchPrepared = false; + + static u32 irOrigReadingCode[5] = { + 0xE5940000, // ldr r0, [r4] + 0xE1A01005, // mov r1, r5 + 0xE3A03005, // mov r3, #5 + 0xE3A02011, // mov r2, #17 + 0x00000000 // (bl i2c_read_raw goes here) + }; + + static u32 irHook[] = { + 0xE5940000, // ldr r0, [r4] + 0xE1A01005, // mov r1, r5 + 0xE59FC000, // ldr r12, [pc] (actually +8) + 0xE12FFF3C, // blx r12 + 0x00000000 // irCodePhys goes here + }; + + static u32 syncHookCode[] = { + 0xE5900000, // ldr r0, [r0] + 0xEF000024, // svc 0x24 + 0xE3A00000, // mov r0, #0 + 0xE51FF004, // ldr pc, [pc, #-4] + 0x00000000, // (return address goes here) + }; + + // Find offsets for required patches + s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; + u32 totalSize; + Result res; + + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + + totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); + + svcGetProcessInfo(&startAddress, processHandle, 0x10005); + res = svcMapProcessMemoryEx(processHandle, 0x00100000, (u32) startAddress, totalSize); + + if(R_SUCCEEDED(res) && !patchPrepared) + { + static const u32 irOrigWaitSyncCode[] = { + 0xEF000024, // svc 0x24 (WaitSynchronization) + 0xE1B01FA0, // movs r1, r0, lsr#31 + 0xE1A0A000, // mov r10, r0 + }, irOrigWaitSyncCodeOld[] = { + 0xE0AC6000, // adc r6, r12, r0 + 0xE5D70000, // ldrb r0, [r7] + }; // pattern for 8.1 + + static const u32 irOrigCppFlagCode[] = { + 0xE3550000, // cmp r5, #0 + 0xE3A0B080, // mov r11, #0x80 + }; + + u32 irDataPhys = (u32)PA_FROM_VA_PTR(irData); + u32 irCodePhys = (u32)PA_FROM_VA_PTR(&irCodePatchFunc); + + u32 *off = (u32 *)memsearch((u8 *)0x00100000, &irOrigReadingCode, totalSize, sizeof(irOrigReadingCode) - 4); + if(off == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -1; + } + + u32 *off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCode, totalSize, sizeof(irOrigWaitSyncCode)); + if(off2 == NULL) + { + off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCodeOld, totalSize, sizeof(irOrigWaitSyncCodeOld)); + if(off2 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -2; + } + } + + u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &irOrigCppFlagCode, totalSize, sizeof(irOrigCppFlagCode)); + if(off3 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -3; + } + + origIrSync = *off2; + origCppFlag = *off3; + + *(void **)(irCodePhys + 8) = decodeArmBranch(off + 4); + *(void **)(irCodePhys + 12) = (void*)irDataPhys; + + irHook[4] = irCodePhys; + irOrigReadingCode[4] = off[4]; // Copy the branch. + syncHookCode[4] = (u32)off2 + 4; // Hook return address + + hookLoc = PA_FROM_VA_PTR(off); + syncLoc = PA_FROM_VA_PTR(off2); + cppFlagLoc = PA_FROM_VA_PTR(off3); + + patchPrepared = true; + } + + if (R_SUCCEEDED(res)) + { + if (doPatch) + { + memcpy(hookLoc, &irHook, sizeof(irHook)); + + // We keep the WaitSynchronization1 to avoid general slowdown because of the high cpu load + if (*syncLoc == 0xEF000024) // svc 0x24 (WaitSynchronization) + { + syncLoc[-1] = 0xE51FF004; + syncLoc[0] = (u32)PA_FROM_VA_PTR(&syncHookCode); + } + else + { + // This "NOP"s out a WaitSynchronisation1 (on the event bound to the 'IR' interrupt) or the check of a previous one + *syncLoc = 0xE3A00000; // mov r0, #0 + } + + // This NOPs out a flag check in ir:user's CPP emulation + *cppFlagLoc = 0xE3150000; // tst r5, #0 + } + else + { + memcpy(hookLoc, irOrigReadingCode, sizeof(irOrigReadingCode)); + + if (*syncLoc == 0xE3A00000) + *syncLoc = origIrSync; + else + { + syncLoc[-1] = 0xE5900000; // ldr r0, [r0] + syncLoc[0] = 0xEF000024; // svc 0x24 + } + + *cppFlagLoc = origCppFlag; + } + } + + svcInvalidateEntireInstructionCache(); + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + + return res; +} + +static Result InputRedirection_DoUndoHidPatches(Handle processHandle, bool doPatches) +{ + static const u32 hidOrigRegisterAndValue[] = { 0x1EC46000, 0x4001 }; + static const u32 hidOrigCode[] = { + 0xE92D4070, // push {r4-r6, lr} + 0xE1A05001, // mov r5, r1 + 0xEE1D4F70, // mrc p15, 0, r4, c13, c0, 3 + 0xE3A01801, // mov r1, #0x10000 + 0xE5A41080, // str r1, [r4,#0x80]! + }; + + static bool patchPrepared = false; + static u32 *hidRegPatchOffsets[2]; + static u32 *hidPatchJumpLoc; + + // Find offsets for required patches + s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; + u32 totalSize; + Result res; + + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + + totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); + + svcGetProcessInfo(&startAddress, processHandle, 0x10005); + res = svcMapProcessMemoryEx(processHandle, 0x00100000, (u32) startAddress, totalSize); + + if (R_SUCCEEDED(res) && !patchPrepared) + { + u32 *off = (u32 *)memsearch((u8 *)0x00100000, &hidOrigRegisterAndValue, totalSize, sizeof(hidOrigRegisterAndValue)); + if(off == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -1; + } + + u32 *off2 = (u32 *)memsearch((u8 *)off + sizeof(hidOrigRegisterAndValue), &hidOrigRegisterAndValue, totalSize - ((u32)off - 0x00100000), sizeof(hidOrigRegisterAndValue)); + if(off2 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -2; + } + + u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &hidOrigCode, totalSize, sizeof(hidOrigCode)); + if(off3 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -3; + } + + hidRegPatchOffsets[0] = off; + hidRegPatchOffsets[1] = off2; + hidPatchJumpLoc = off3; + + patchPrepared = true; + } + + if(R_SUCCEEDED(res)) + { + if (doPatches) + { + u32 hidDataPhys = (u32)PA_FROM_VA_PTR(hidData); + u32 hidCodePhys = (u32)PA_FROM_VA_PTR(&hidCodePatchFunc); + u32 hidHook[] = { + 0xE59F3004, // ldr r3, [pc, #4] + 0xE59FC004, // ldr r12, [pc, #4] + 0xE12FFF1C, // bx r12 + hidDataPhys, + hidCodePhys, + }; + + *hidRegPatchOffsets[0] = *hidRegPatchOffsets[1] = hidDataPhys; + memcpy(hidPatchJumpLoc, &hidHook, sizeof(hidHook)); + } + else + { + memcpy(hidRegPatchOffsets[0], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue)); + memcpy(hidRegPatchOffsets[1], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue)); + memcpy(hidPatchJumpLoc, &hidOrigCode, sizeof(hidOrigCode)); + } + } + + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return res; +} + Result InputRedirection_Disable(s64 timeout) { if(!inputRedirectionEnabled) @@ -186,209 +426,46 @@ Result InputRedirection_Disable(s64 timeout) Result InputRedirection_DoOrUndoPatches(void) { - s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; - u32 totalSize; - Handle processHandle; - - Result res = OpenProcessByName("hid", &processHandle); static bool hidPatched = false; static bool irPatched = false; + Handle hidProcHandle = 0, irProcHandle = 0; + + // Prevent hid and ir from running, in any case + + svcKernelSetState(0x10000, 4); + + Result res = OpenProcessByName("hid", &hidProcHandle); + if (R_FAILED(res)) + goto cleanup; + + res = OpenProcessByName("ir", &irProcHandle); + if (R_FAILED(res)) + goto cleanup; + if(R_SUCCEEDED(res)) { - svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data - svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); - svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); - - totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); - - svcGetProcessInfo(&startAddress, processHandle, 0x10005); - res = svcMapProcessMemoryEx(processHandle, 0x00100000, (u32) startAddress, totalSize); - - if(R_SUCCEEDED(res)) - { - static const u32 hidOrigRegisterAndValue[] = { 0x1EC46000, 0x4001 }; - static const u32 hidOrigCode[] = { - 0xE92D4070, // push {r4-r6, lr} - 0xE1A05001, // mov r5, r1 - 0xEE1D4F70, // mrc p15, 0, r4, c13, c0, 3 - 0xE3A01801, // mov r1, #0x10000 - 0xE5A41080, // str r1, [r4,#0x80]! - }; - - static u32 *hidRegPatchOffsets[2]; - static u32 *hidPatchJumpLoc; - - if(hidPatched) - { - memcpy(hidRegPatchOffsets[0], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue)); - memcpy(hidRegPatchOffsets[1], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue)); - memcpy(hidPatchJumpLoc, &hidOrigCode, sizeof(hidOrigCode)); - hidPatched = false; - } - else - { - u32 hidDataPhys = (u32)PA_FROM_VA_PTR(hidData); - u32 hidCodePhys = (u32)PA_FROM_VA_PTR(&hidCodePatchFunc); - u32 hidHook[] = { - 0xE59F3004, // ldr r3, [pc, #4] - 0xE59FC004, // ldr r12, [pc, #4] - 0xE12FFF1C, // bx r12 - hidDataPhys, - hidCodePhys, - }; - - u32 *off = (u32 *)memsearch((u8 *)0x00100000, &hidOrigRegisterAndValue, totalSize, sizeof(hidOrigRegisterAndValue)); - if(off == NULL) - { - svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); - return -1; - } - - u32 *off2 = (u32 *)memsearch((u8 *)off + sizeof(hidOrigRegisterAndValue), &hidOrigRegisterAndValue, totalSize - ((u32)off - 0x00100000), sizeof(hidOrigRegisterAndValue)); - if(off2 == NULL) - { - svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); - return -2; - } - - u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &hidOrigCode, totalSize, sizeof(hidOrigCode)); - if(off3 == NULL) - { - svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); - return -3; - } - - hidRegPatchOffsets[0] = off; - hidRegPatchOffsets[1] = off2; - hidPatchJumpLoc = off3; - - *off = *off2 = hidDataPhys; - memcpy(off3, &hidHook, sizeof(hidHook)); - hidPatched = true; - } - } - - res = svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + res = InputRedirection_DoUndoHidPatches(hidProcHandle, !hidPatched); + if (R_SUCCEEDED(res)) + hidPatched = !hidPatched; } - svcCloseHandle(processHandle); - res = OpenProcessByName("ir", &processHandle); if(R_SUCCEEDED(res) && GET_VERSION_MINOR(osGetKernelVersion()) >= 44) { - svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data - svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); - svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); - - totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); - - svcGetProcessInfo(&startAddress, processHandle, 0x10005); - res = svcMapProcessMemoryEx(processHandle, 0x00100000, (u32) startAddress, totalSize); - - if(R_SUCCEEDED(res)) + res = InputRedirection_DoUndoIrPatches(irProcHandle, !irPatched); + if (R_SUCCEEDED(res)) + irPatched = !irPatched; + else if (!irPatched) { - static bool useOldSyncCode; - static u32 irOrigReadingCode[5] = { - 0xE5940000, // ldr r0, [r4] - 0xE1A01005, // mov r1, r5 - 0xE3A03005, // mov r3, #5 - 0xE3A02011, // mov r2, #17 - 0x00000000 // (bl i2c_read_raw goes here) - }; - - static const u32 irOrigWaitSyncCode[] = { - 0xEF000024, // svc 0x24 (WaitSynchronization) - 0xE1B01FA0, // movs r1, r0, lsr#31 - 0xE1A0A000, // mov r10, r0 - }, irOrigWaitSyncCodeOld[] = { - 0xE0AC6000, // adc r6, r12, r0 - 0xE5D70000, // ldrb r0, [r7] - }; // pattern for 8.1 - - static const u32 irOrigCppFlagCode[] = { - 0xE3550000, // cmp r5, #0 - 0xE3A0B080, // mov r11, #0x80 - }; - - static u32 *irHookLoc, *irWaitSyncLoc, *irCppFlagLoc; - - if(irPatched) - { - memcpy(irHookLoc, &irOrigReadingCode, sizeof(irOrigReadingCode)); - if(useOldSyncCode) - memcpy(irWaitSyncLoc, &irOrigWaitSyncCodeOld, sizeof(irOrigWaitSyncCodeOld)); - else - memcpy(irWaitSyncLoc, &irOrigWaitSyncCode, sizeof(irOrigWaitSyncCode)); - memcpy(irCppFlagLoc, &irOrigCppFlagCode, sizeof(irOrigCppFlagCode)); - - irPatched = false; - } - else - { - u32 irDataPhys = (u32)PA_FROM_VA_PTR(irData); - u32 irCodePhys = (u32)PA_FROM_VA_PTR(&irCodePatchFunc); - - u32 irHook[] = { - 0xE5940000, // ldr r0, [r4] - 0xE1A01005, // mov r1, r5 - 0xE59FC000, // ldr r12, [pc] (actually +8) - 0xE12FFF3C, // blx r12 - irCodePhys, - }; - - u32 *off = (u32 *)memsearch((u8 *)0x00100000, &irOrigReadingCode, totalSize, sizeof(irOrigReadingCode) - 4); - if(off == NULL) - { - svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); - return -4; - } - - u32 *off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCode, totalSize, sizeof(irOrigWaitSyncCode)); - if(off2 == NULL) - { - off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCodeOld, totalSize, sizeof(irOrigWaitSyncCodeOld)); - if(off2 == NULL) - { - svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); - return -5; - } - - useOldSyncCode = true; - } - else - useOldSyncCode = false; - - u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &irOrigCppFlagCode, totalSize, sizeof(irOrigCppFlagCode)); - if(off3 == NULL) - { - svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); - return -6; - } - - *(void **)(irCodePhys + 8) = decodeArmBranch(off + 4); - *(void **)(irCodePhys + 12) = (void*)irDataPhys; - - irHookLoc = off; - irWaitSyncLoc = off2; - irCppFlagLoc = off3; - - irOrigReadingCode[4] = off[4]; // Copy the branch. - - memcpy(irHookLoc, &irHook, sizeof(irHook)); - - // This "NOP"s out a WaitSynchronisation1 (on the event bound to the 'IR' interrupt) or the check of a previous one - *irWaitSyncLoc = 0xE3A00000; // mov r0, #0 - - // This NOPs out a flag check in ir:user's CPP emulation - *irCppFlagLoc = 0xE3150000; // tst r5, #0 - - irPatched = true; - } + InputRedirection_DoUndoHidPatches(hidProcHandle, false); + hidPatched = false; } - - res = svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); } - svcCloseHandle(processHandle); +cleanup: + svcKernelSetState(0x10000, 4); + + svcCloseHandle(hidProcHandle); + svcCloseHandle(irProcHandle); return res; }