Skip to content

Commit

Permalink
Allow plugins to use PRIVATE memory instead of SHARED on requests (#2086
Browse files Browse the repository at this point in the history
)

- 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 <[email protected]>
  • Loading branch information
PabloMK7 and LittleCube-hax authored Sep 27, 2024
1 parent e0e86c4 commit 3253fdb
Show file tree
Hide file tree
Showing 13 changed files with 47 additions and 21 deletions.
10 changes: 8 additions & 2 deletions k11_extension/include/svc/MapProcessMemoryEx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
4 changes: 2 additions & 2 deletions k11_extension/source/svc/MapProcessMemoryEx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
10 changes: 7 additions & 3 deletions k11_extension/source/svc/wrappers.s
Original file line number Diff line number Diff line change
Expand Up @@ -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}
add sp, #8
pop {r5, pc}
10 changes: 9 additions & 1 deletion sysmodules/rosalina/include/csvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,23 @@ 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)
* @param destAddress Start address of the memory block in the destination process
* @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.
Expand Down
3 changes: 2 additions & 1 deletion sysmodules/rosalina/include/plugin/3gx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions sysmodules/rosalina/include/plugin/plgloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ typedef struct
u32 swapLoadChecksum;

bool eventsSelfManaged;
bool isMemPrivate;
} PluginLoaderContext;

extern PluginLoaderContext PluginLoaderCtx;
Expand Down
9 changes: 6 additions & 3 deletions sysmodules/rosalina/source/csvc.s
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions sysmodules/rosalina/source/input_redirection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down
4 changes: 2 additions & 2 deletions sysmodules/rosalina/source/menus/process_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion sysmodules/rosalina/source/plugin/file_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 4 additions & 3 deletions sysmodules/rosalina/source/plugin/memoryblock.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,19 +205,20 @@ 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;
return res;
}

// 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;
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions sysmodules/rosalina/source/plugin/plgloader.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion sysmodules/rosalina/source/process_patches.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 3253fdb

Please sign in to comment.