From 3253fdb255b311455625db2b89f23137981230df Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Fri, 27 Sep 2024 20:31:03 +0000 Subject: [PATCH] Allow plugins to use PRIVATE memory instead of SHARED on requests (#2086) - Modify the svcMapProcessMemoryEx svc so that it takes an extra flags argument. This change was made in a way that shouldn't break existing plugins or applications. - Add MAPEXFLAGS_PRIVATE flag, which maps the specified memory as PRIVATE instead of SHARED. - Allow plugins to be mapped with PRIVATE memory instead of SHARED with a flag in the .3gx header. This allows plugins to use socket and http services without additional hacks. --------- Co-authored-by: LittleCube --- k11_extension/include/svc/MapProcessMemoryEx.h | 10 ++++++++-- k11_extension/source/svc/MapProcessMemoryEx.c | 4 ++-- k11_extension/source/svc/wrappers.s | 10 +++++++--- sysmodules/rosalina/include/csvc.h | 10 +++++++++- sysmodules/rosalina/include/plugin/3gx.h | 3 ++- sysmodules/rosalina/include/plugin/plgloader.h | 1 + sysmodules/rosalina/source/csvc.s | 9 ++++++--- sysmodules/rosalina/source/input_redirection.c | 4 ++-- sysmodules/rosalina/source/menus/process_list.c | 4 ++-- sysmodules/rosalina/source/plugin/file_loader.c | 3 ++- sysmodules/rosalina/source/plugin/memoryblock.c | 7 ++++--- sysmodules/rosalina/source/plugin/plgloader.c | 1 + sysmodules/rosalina/source/process_patches.c | 2 +- 13 files changed, 47 insertions(+), 21 deletions(-) diff --git a/k11_extension/include/svc/MapProcessMemoryEx.h b/k11_extension/include/svc/MapProcessMemoryEx.h index 0b357afd1..c97c348a0 100644 --- a/k11_extension/include/svc/MapProcessMemoryEx.h +++ b/k11_extension/include/svc/MapProcessMemoryEx.h @@ -30,5 +30,11 @@ #include "kernel.h" #include "svc.h" -Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size); -Result MapProcessMemoryExWrapper(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size); +/// Flags for svcMapProcessMemoryEx +typedef enum MapExFlags +{ + MAPEXFLAGS_PRIVATE = BIT(0), ///< Maps the memory as PRIVATE (0xBB05) instead of SHARED (0x5806) +} MapExFlags; + +Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size, MapExFlags flags); +Result MapProcessMemoryExWrapper(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size, MapExFlags flags); diff --git a/k11_extension/source/svc/MapProcessMemoryEx.c b/k11_extension/source/svc/MapProcessMemoryEx.c index 5d0da1674..05baf1a96 100644 --- a/k11_extension/source/svc/MapProcessMemoryEx.c +++ b/k11_extension/source/svc/MapProcessMemoryEx.c @@ -26,7 +26,7 @@ #include "svc/MapProcessMemoryEx.h" -Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size) +Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size, MapExFlags flags) { Result res = 0; u32 sizeInPage = size >> 12; @@ -69,7 +69,7 @@ Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcess // Check if the destination address is free and large enough res = KProcessHwInfo__CheckVaState(hwInfoOfProcess(dstProcess), vaDst, size, 0, 0); if (res == 0) - res = KProcessHwInfo__MapListOfKBlockInfo(hwInfoOfProcess(dstProcess), vaDst, &list, 0x5806, MEMPERM_RW | 0x18, 0); + res = KProcessHwInfo__MapListOfKBlockInfo(hwInfoOfProcess(dstProcess), vaDst, &list, (flags & MAPEXFLAGS_PRIVATE) ? 0xBB05 : 0x5806, MEMPERM_RW | 0x18, 0); } KLinkedList_KBlockInfo__Clear(&list); diff --git a/k11_extension/source/svc/wrappers.s b/k11_extension/source/svc/wrappers.s index 6d07ccde8..43652bf7e 100644 --- a/k11_extension/source/svc/wrappers.s +++ b/k11_extension/source/svc/wrappers.s @@ -118,8 +118,12 @@ ControlMemoryUnsafeWrapper: .global MapProcessMemoryExWrapper .type MapProcessMemoryExWrapper, %function MapProcessMemoryExWrapper: - push {lr} + push {r5, lr} @ We need to save r5 because the old implementation doesn't save it + cmp r0, #0xFFFFFFF2 @ Check magic value, for backwards compatibility + moveq r0, r6 @ If value present, flags present in r5 and dst process in r6, so move dst process back to r0 + movne r5, #0 @ If value not present, clear the flags as its the old version + str r5, [sp, #-4]! str r4, [sp, #-4]! bl MapProcessMemoryEx - add sp, #4 - pop {pc} \ No newline at end of file + add sp, #8 + pop {r5, pc} \ No newline at end of file diff --git a/sysmodules/rosalina/include/csvc.h b/sysmodules/rosalina/include/csvc.h index f6d8ce989..8965a9db4 100644 --- a/sysmodules/rosalina/include/csvc.h +++ b/sysmodules/rosalina/include/csvc.h @@ -73,6 +73,13 @@ void svcInvalidateEntireInstructionCache(void); ///@name Memory management ///@{ + +/// Flags for svcMapProcessMemoryEx +typedef enum MapExFlags +{ + MAPEXFLAGS_PRIVATE = BIT(0), ///< Maps the memory as PRIVATE (0xBB05) instead of SHARED (0x5806) +} MapExFlags; + /** * @brief Maps a block of process memory. * @param dstProcessHandle Handle of the process to map the memory in (destination) @@ -80,8 +87,9 @@ void svcInvalidateEntireInstructionCache(void); * @param srcProcessHandle Handle of the process to map the memory from (source) * @param srcAddress Start address of the memory block in the source process * @param size Size of the block of the memory to map (truncated to a multiple of 0x1000 bytes) + * @param flags Extended flags for mapping the memory (see MapExFlags) */ -Result svcMapProcessMemoryEx(Handle dstProcessHandle, u32 destAddress, Handle srcProcessHandle, u32 srcAddress, u32 size); +Result svcMapProcessMemoryEx(Handle dstProcessHandle, u32 destAddress, Handle srcProcessHandle, u32 srcAddress, u32 size, MapExFlags flags); /** * @brief Unmaps a block of process memory. diff --git a/sysmodules/rosalina/include/plugin/3gx.h b/sysmodules/rosalina/include/plugin/3gx.h index 738fa8a65..d14030953 100644 --- a/sysmodules/rosalina/include/plugin/3gx.h +++ b/sysmodules/rosalina/include/plugin/3gx.h @@ -23,7 +23,8 @@ typedef struct CTR_PACKED u32 compatibility : 2; u32 eventsSelfManaged : 1; u32 swapNotNeeded : 1; - u32 unused : 24; + u32 usePrivateMemory : 1; + u32 unused : 23; }; }; u32 exeLoadChecksum; diff --git a/sysmodules/rosalina/include/plugin/plgloader.h b/sysmodules/rosalina/include/plugin/plgloader.h index 2f0b95fdf..7178bf133 100644 --- a/sysmodules/rosalina/include/plugin/plgloader.h +++ b/sysmodules/rosalina/include/plugin/plgloader.h @@ -93,6 +93,7 @@ typedef struct u32 swapLoadChecksum; bool eventsSelfManaged; + bool isMemPrivate; } PluginLoaderContext; extern PluginLoaderContext PluginLoaderCtx; diff --git a/sysmodules/rosalina/source/csvc.s b/sysmodules/rosalina/source/csvc.s index da6987533..3a91db9d0 100644 --- a/sysmodules/rosalina/source/csvc.s +++ b/sysmodules/rosalina/source/csvc.s @@ -59,10 +59,13 @@ SVC_BEGIN svcInvalidateEntireInstructionCache SVC_END SVC_BEGIN svcMapProcessMemoryEx - str r4, [sp, #-4]! - ldr r4, [sp, #4] + push {r4, r5, r6} + ldr r4, [sp, #12] + ldr r5, [sp, #16] + mov r6, r0 @ Move the dst handle to r6 to make room for magic value + mov r0, #0xFFFFFFF2 @ Set r0 to magic value, which allows for backwards compatibility svc 0xA0 - ldr r4, [sp], #4 + pop {r4, r5, r6} bx lr SVC_END diff --git a/sysmodules/rosalina/source/input_redirection.c b/sysmodules/rosalina/source/input_redirection.c index 50037d1bd..60c18213e 100644 --- a/sysmodules/rosalina/source/input_redirection.c +++ b/sysmodules/rosalina/source/input_redirection.c @@ -223,7 +223,7 @@ static Result InputRedirection_DoUndoIrPatches(Handle processHandle, bool doPatc totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); svcGetProcessInfo(&startAddress, processHandle, 0x10005); - res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize); + res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize, 0); if(R_SUCCEEDED(res) && !patchPrepared) { @@ -356,7 +356,7 @@ static Result InputRedirection_DoUndoHidPatches(Handle processHandle, bool doPat totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); svcGetProcessInfo(&startAddress, processHandle, 0x10005); - res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize); + res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize, 0); if (R_SUCCEEDED(res) && !patchPrepared) { diff --git a/sysmodules/rosalina/source/menus/process_list.c b/sysmodules/rosalina/source/menus/process_list.c index cbe080178..de3133161 100644 --- a/sysmodules/rosalina/source/menus/process_list.c +++ b/sysmodules/rosalina/source/menus/process_list.c @@ -245,8 +245,8 @@ static void ProcessListMenu_MemoryViewer(const ProcessInfo *info) svcQueryProcessMemory(&mem, &out, processHandle, heapStartAddress); heapTotalSize = mem.size; - Result codeRes = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, codeDestAddress, processHandle, codeStartAddress, codeTotalSize); - Result heapRes = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, heapDestAddress, processHandle, heapStartAddress, heapTotalSize); + Result codeRes = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, codeDestAddress, processHandle, codeStartAddress, codeTotalSize, 0); + Result heapRes = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, heapDestAddress, processHandle, heapStartAddress, heapTotalSize, 0); bool codeAvailable = R_SUCCEEDED(codeRes); bool heapAvailable = R_SUCCEEDED(heapRes); diff --git a/sysmodules/rosalina/source/plugin/file_loader.c b/sysmodules/rosalina/source/plugin/file_loader.c index 1a21946fa..6bea9bda6 100644 --- a/sysmodules/rosalina/source/plugin/file_loader.c +++ b/sysmodules/rosalina/source/plugin/file_loader.c @@ -214,6 +214,7 @@ bool TryToLoadPlugin(Handle process) // Flags if (!res) { ctx->eventsSelfManaged = fileHeader.infos.eventsSelfManaged; + ctx->isMemPrivate = fileHeader.infos.usePrivateMemory; if (ctx->pluginMemoryStrategy == PLG_STRATEGY_SWAP && fileHeader.infos.swapNotNeeded) ctx->pluginMemoryStrategy = PLG_STRATEGY_NONE; } @@ -292,7 +293,7 @@ bool TryToLoadPlugin(Handle process) extern u32 g_savedGameInstr[2]; - if (R_FAILED((res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, procStart, process, procStart, 0x1000)))) + if (R_FAILED((res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, procStart, process, procStart, 0x1000, 0)))) { ctx->error.message = "Couldn't map process"; ctx->error.code = res; diff --git a/sysmodules/rosalina/source/plugin/memoryblock.c b/sysmodules/rosalina/source/plugin/memoryblock.c index 8738f1efd..07bc576b8 100644 --- a/sysmodules/rosalina/source/plugin/memoryblock.c +++ b/sysmodules/rosalina/source/plugin/memoryblock.c @@ -205,11 +205,12 @@ Result MemoryBlock__MountInProcess(void) Error *error = &PluginLoaderCtx.error; PluginHeader *header = &PluginLoaderCtx.header; MemoryBlock *memblock = &PluginLoaderCtx.memblock; + bool isPrivate = PluginLoaderCtx.isMemPrivate; Result res = 0; // Executable - if (R_FAILED((res = svcMapProcessMemoryEx(target, 0x07000000, CUR_PROCESS_HANDLE, (u32)memblock->memblock, header->exeSize)))) + if (R_FAILED((res = svcMapProcessMemoryEx(target, 0x07000000, CUR_PROCESS_HANDLE, (u32) memblock->memblock, header->exeSize, isPrivate ? MAPEXFLAGS_PRIVATE : 0)))) { error->message = "Couldn't map exe memory block"; error->code = res; @@ -217,7 +218,7 @@ Result MemoryBlock__MountInProcess(void) } // Heap (to be used by the plugin) - if (R_FAILED((res = svcMapProcessMemoryEx(target, header->heapVA, CUR_PROCESS_HANDLE, (u32)memblock->memblock + header->exeSize, header->heapSize)))) + if (R_FAILED((res = svcMapProcessMemoryEx(target, header->heapVA, CUR_PROCESS_HANDLE, (u32) memblock->memblock + header->exeSize, header->heapSize, isPrivate ? MAPEXFLAGS_PRIVATE : 0)))) { error->message = "Couldn't map heap memory block"; error->code = res; @@ -233,7 +234,7 @@ Result MemoryBlock__UnmountFromProcess(void) Result res = 0; - res = svcUnmapProcessMemoryEx(target, 0x07000000, header->exeSize); + res |= svcUnmapProcessMemoryEx(target, 0x07000000, header->exeSize); res |= svcUnmapProcessMemoryEx(target, header->heapVA, header->heapSize); return res; diff --git a/sysmodules/rosalina/source/plugin/plgloader.c b/sysmodules/rosalina/source/plugin/plgloader.c index 55e5ec8ff..f3aea9918 100644 --- a/sysmodules/rosalina/source/plugin/plgloader.c +++ b/sysmodules/rosalina/source/plugin/plgloader.c @@ -558,6 +558,7 @@ static void WaitForProcessTerminated(void *arg) ctx->isSwapFunctionset = false; ctx->pluginMemoryStrategy = PLG_STRATEGY_SWAP; ctx->eventsSelfManaged = false; + ctx->isMemPrivate = false; g_blockMenuOpen = 0; MemoryBlock__ResetSwapSettings(); //if (!ctx->userLoadParameters.noIRPatch) diff --git a/sysmodules/rosalina/source/process_patches.c b/sysmodules/rosalina/source/process_patches.c index e72ecf670..41cf608d6 100644 --- a/sysmodules/rosalina/source/process_patches.c +++ b/sysmodules/rosalina/source/process_patches.c @@ -77,7 +77,7 @@ Result OperateOnProcessByName(const char *name, OperateOnProcessCb func) // NOTE: we suppose .text, .rodata, .data+.bss are contiguous & in that order u32 totalSize = (u32)(textSize + roSize + rwSize); - if (R_FAILED(res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize))) + if (R_FAILED(res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize, 0))) { svcCloseHandle(processHandle); return res;