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 <littlecubehax@gmail.com>
This commit is contained in:
PabloMK7 2024-09-27 20:31:03 +00:00 committed by GitHub
parent e0e86c46a7
commit 3253fdb255
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 47 additions and 21 deletions

View File

@ -30,5 +30,11 @@
#include "kernel.h" #include "kernel.h"
#include "svc.h" #include "svc.h"
Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size); /// Flags for svcMapProcessMemoryEx
Result MapProcessMemoryExWrapper(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size); 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);

View File

@ -26,7 +26,7 @@
#include "svc/MapProcessMemoryEx.h" #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; Result res = 0;
u32 sizeInPage = size >> 12; 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 // Check if the destination address is free and large enough
res = KProcessHwInfo__CheckVaState(hwInfoOfProcess(dstProcess), vaDst, size, 0, 0); res = KProcessHwInfo__CheckVaState(hwInfoOfProcess(dstProcess), vaDst, size, 0, 0);
if (res == 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); KLinkedList_KBlockInfo__Clear(&list);

View File

@ -118,8 +118,12 @@ ControlMemoryUnsafeWrapper:
.global MapProcessMemoryExWrapper .global MapProcessMemoryExWrapper
.type MapProcessMemoryExWrapper, %function .type MapProcessMemoryExWrapper, %function
MapProcessMemoryExWrapper: 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]! str r4, [sp, #-4]!
bl MapProcessMemoryEx bl MapProcessMemoryEx
add sp, #4 add sp, #8
pop {pc} pop {r5, pc}

View File

@ -73,6 +73,13 @@ void svcInvalidateEntireInstructionCache(void);
///@name Memory management ///@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. * @brief Maps a block of process memory.
* @param dstProcessHandle Handle of the process to map the memory in (destination) * @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 srcProcessHandle Handle of the process to map the memory from (source)
* @param srcAddress Start address of the memory block in the source process * @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 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. * @brief Unmaps a block of process memory.

View File

@ -23,7 +23,8 @@ typedef struct CTR_PACKED
u32 compatibility : 2; u32 compatibility : 2;
u32 eventsSelfManaged : 1; u32 eventsSelfManaged : 1;
u32 swapNotNeeded : 1; u32 swapNotNeeded : 1;
u32 unused : 24; u32 usePrivateMemory : 1;
u32 unused : 23;
}; };
}; };
u32 exeLoadChecksum; u32 exeLoadChecksum;

View File

@ -93,6 +93,7 @@ typedef struct
u32 swapLoadChecksum; u32 swapLoadChecksum;
bool eventsSelfManaged; bool eventsSelfManaged;
bool isMemPrivate;
} PluginLoaderContext; } PluginLoaderContext;
extern PluginLoaderContext PluginLoaderCtx; extern PluginLoaderContext PluginLoaderCtx;

View File

@ -59,10 +59,13 @@ SVC_BEGIN svcInvalidateEntireInstructionCache
SVC_END SVC_END
SVC_BEGIN svcMapProcessMemoryEx SVC_BEGIN svcMapProcessMemoryEx
str r4, [sp, #-4]! push {r4, r5, r6}
ldr r4, [sp, #4] 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 svc 0xA0
ldr r4, [sp], #4 pop {r4, r5, r6}
bx lr bx lr
SVC_END SVC_END

View File

@ -223,7 +223,7 @@ static Result InputRedirection_DoUndoIrPatches(Handle processHandle, bool doPatc
totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize);
svcGetProcessInfo(&startAddress, processHandle, 0x10005); 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) if(R_SUCCEEDED(res) && !patchPrepared)
{ {
@ -356,7 +356,7 @@ static Result InputRedirection_DoUndoHidPatches(Handle processHandle, bool doPat
totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize);
svcGetProcessInfo(&startAddress, processHandle, 0x10005); 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) if (R_SUCCEEDED(res) && !patchPrepared)
{ {

View File

@ -245,8 +245,8 @@ static void ProcessListMenu_MemoryViewer(const ProcessInfo *info)
svcQueryProcessMemory(&mem, &out, processHandle, heapStartAddress); svcQueryProcessMemory(&mem, &out, processHandle, heapStartAddress);
heapTotalSize = mem.size; heapTotalSize = mem.size;
Result codeRes = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, codeDestAddress, processHandle, codeStartAddress, codeTotalSize); Result codeRes = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, codeDestAddress, processHandle, codeStartAddress, codeTotalSize, 0);
Result heapRes = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, heapDestAddress, processHandle, heapStartAddress, heapTotalSize); Result heapRes = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, heapDestAddress, processHandle, heapStartAddress, heapTotalSize, 0);
bool codeAvailable = R_SUCCEEDED(codeRes); bool codeAvailable = R_SUCCEEDED(codeRes);
bool heapAvailable = R_SUCCEEDED(heapRes); bool heapAvailable = R_SUCCEEDED(heapRes);

View File

@ -214,6 +214,7 @@ bool TryToLoadPlugin(Handle process)
// Flags // Flags
if (!res) { if (!res) {
ctx->eventsSelfManaged = fileHeader.infos.eventsSelfManaged; ctx->eventsSelfManaged = fileHeader.infos.eventsSelfManaged;
ctx->isMemPrivate = fileHeader.infos.usePrivateMemory;
if (ctx->pluginMemoryStrategy == PLG_STRATEGY_SWAP && fileHeader.infos.swapNotNeeded) if (ctx->pluginMemoryStrategy == PLG_STRATEGY_SWAP && fileHeader.infos.swapNotNeeded)
ctx->pluginMemoryStrategy = PLG_STRATEGY_NONE; ctx->pluginMemoryStrategy = PLG_STRATEGY_NONE;
} }
@ -292,7 +293,7 @@ bool TryToLoadPlugin(Handle process)
extern u32 g_savedGameInstr[2]; 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.message = "Couldn't map process";
ctx->error.code = res; ctx->error.code = res;

View File

@ -205,11 +205,12 @@ Result MemoryBlock__MountInProcess(void)
Error *error = &PluginLoaderCtx.error; Error *error = &PluginLoaderCtx.error;
PluginHeader *header = &PluginLoaderCtx.header; PluginHeader *header = &PluginLoaderCtx.header;
MemoryBlock *memblock = &PluginLoaderCtx.memblock; MemoryBlock *memblock = &PluginLoaderCtx.memblock;
bool isPrivate = PluginLoaderCtx.isMemPrivate;
Result res = 0; Result res = 0;
// Executable // 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->message = "Couldn't map exe memory block";
error->code = res; error->code = res;
@ -217,7 +218,7 @@ Result MemoryBlock__MountInProcess(void)
} }
// Heap (to be used by the plugin) // 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->message = "Couldn't map heap memory block";
error->code = res; error->code = res;
@ -233,7 +234,7 @@ Result MemoryBlock__UnmountFromProcess(void)
Result res = 0; Result res = 0;
res = svcUnmapProcessMemoryEx(target, 0x07000000, header->exeSize); res |= svcUnmapProcessMemoryEx(target, 0x07000000, header->exeSize);
res |= svcUnmapProcessMemoryEx(target, header->heapVA, header->heapSize); res |= svcUnmapProcessMemoryEx(target, header->heapVA, header->heapSize);
return res; return res;

View File

@ -558,6 +558,7 @@ static void WaitForProcessTerminated(void *arg)
ctx->isSwapFunctionset = false; ctx->isSwapFunctionset = false;
ctx->pluginMemoryStrategy = PLG_STRATEGY_SWAP; ctx->pluginMemoryStrategy = PLG_STRATEGY_SWAP;
ctx->eventsSelfManaged = false; ctx->eventsSelfManaged = false;
ctx->isMemPrivate = false;
g_blockMenuOpen = 0; g_blockMenuOpen = 0;
MemoryBlock__ResetSwapSettings(); MemoryBlock__ResetSwapSettings();
//if (!ctx->userLoadParameters.noIRPatch) //if (!ctx->userLoadParameters.noIRPatch)

View File

@ -77,7 +77,7 @@ Result OperateOnProcessByName(const char *name, OperateOnProcessCb func)
// NOTE: we suppose .text, .rodata, .data+.bss are contiguous & in that order // NOTE: we suppose .text, .rodata, .data+.bss are contiguous & in that order
u32 totalSize = (u32)(textSize + roSize + rwSize); 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); svcCloseHandle(processHandle);
return res; return res;