PabloMK7 c055fb6f5e
Merge 3GX plugin loader fork (#1916)
This commit adds all the changes made to the 3GX plugin loader fork of Luma3DS. The most important features are:

- Add 3GX plugin loader support. New service added to rosalina: plg:ldr
- Add svcControlProcess, svcControlMemoryUnsafe and improve svcMapProcessMemoryEx (breaking change)
- Allow applications to override certain configurations depending on their needs:
    - Disable core2 thread redirection
    - Disable game patching for the next app
    - Force New 3DS speedup
    - Force next application in a specific memory mode
    - Block the opening of the Rosalina menu
- Add GDB commands to list all process handles and catch all SVC (latter is for IDA Pro as gdb client supports it)
- Other changes necessary for plugins to work properly. Please check changed files in this PR for more details. 

---------

Co-authored-by: PabloMK7 <hackyglitch@gmail.com>
Co-authored-by: Nanquitas <nath.doidi@gmail.com>
Co-authored-by: TuxSH <1922548+TuxSH@users.noreply.github.com>
2023-07-14 20:08:07 +02:00

340 lines
7.7 KiB
C

#include <3ds.h>
#include "plugin.h"
#include <string.h>
#include "csvc.h"
static Handle plgLdrHandle;
static Handle plgLdrArbiter;
static s32* plgEvent;
static s32* plgReply;
static int plgLdrRefCount;
static bool plgIsN3DS;
static OnPlgLdrEventCb_t onPlgLdrEventCb = NULL;
static Result PLGLDR__GetArbiter(void)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(9, 0, 0);
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
plgLdrArbiter = cmdbuf[3];
}
return res;
}
Result plgLdrInit(void)
{
s64 out = 0;
Result res = 0;
svcGetSystemInfo(&out, 0x10000, 0x201);
plgIsN3DS = out != 0;
if (AtomicPostIncrement(&plgLdrRefCount) == 0)
res = svcConnectToPort(&plgLdrHandle, "plg:ldr");
if (R_SUCCEEDED(res)
&& R_SUCCEEDED((res = PLGLDR__GetArbiter())))
{
PluginHeader *header = (PluginHeader *)0x07000000;
plgEvent = header->plgldrEvent;
plgReply = header->plgldrReply;
}
else
plgLdrExit();
return res;
}
void plgLdrExit(void)
{
if (AtomicDecrement(&plgLdrRefCount))
return;
if (plgLdrHandle)
svcCloseHandle(plgLdrHandle);
if (plgLdrArbiter)
svcCloseHandle(plgLdrArbiter);
plgLdrHandle = plgLdrArbiter = 0;
}
Result PLGLDR__IsPluginLoaderEnabled(bool *isEnabled)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(2, 0, 0);
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
*isEnabled = cmdbuf[2];
}
return res;
}
Result PLGLDR__SetPluginLoaderState(bool enabled)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(3, 1, 0);
cmdbuf[1] = (u32)enabled;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
Result PLGLDR__SetPluginLoadParameters(PluginLoadParameters *parameters)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(4, 2, 4);
cmdbuf[1] = (u32)parameters->noFlash | (((u32)parameters->pluginMemoryStrategy) << 8);
cmdbuf[2] = parameters->lowTitleId;
cmdbuf[3] = IPC_Desc_Buffer(256, IPC_BUFFER_R);
cmdbuf[4] = (u32)parameters->path;
cmdbuf[5] = IPC_Desc_Buffer(32 * sizeof(u32), IPC_BUFFER_R);
cmdbuf[6] = (u32)parameters->config;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
void Flash(u32 color);
Result PLGLDR__DisplayMenu(PluginMenu *menu)
{
Result res = 0;
u32 nbItems = menu->nbItems;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(5, 1, 8);
cmdbuf[1] = nbItems;
cmdbuf[2] = IPC_Desc_Buffer(nbItems, IPC_BUFFER_RW);
cmdbuf[3] = (u32)menu->states;
cmdbuf[4] = IPC_Desc_Buffer(MAX_BUFFER, IPC_BUFFER_R);
cmdbuf[5] = (u32)menu->title;
cmdbuf[6] = IPC_Desc_Buffer(MAX_BUFFER * nbItems, IPC_BUFFER_R);
cmdbuf[7] = (u32)menu->items;
cmdbuf[8] = IPC_Desc_Buffer(MAX_BUFFER * nbItems, IPC_BUFFER_R);
cmdbuf[9] = (u32)menu->hints;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
else Flash(0xFF0000);
return res;
}
Result PLGLDR__DisplayMessage(const char *title, const char *body)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(6, 0, 4);
cmdbuf[1] = IPC_Desc_Buffer(strlen(title), IPC_BUFFER_R);
cmdbuf[2] = (u32)title;
cmdbuf[3] = IPC_Desc_Buffer(strlen(body), IPC_BUFFER_R);
cmdbuf[4] = (u32)body;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
Result PLGLDR__DisplayErrMessage(const char *title, const char *body, u32 error)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(7, 1, 4);
cmdbuf[1] = error;
cmdbuf[2] = IPC_Desc_Buffer(strlen(title), IPC_BUFFER_R);
cmdbuf[3] = (u32)title;
cmdbuf[4] = IPC_Desc_Buffer(strlen(body), IPC_BUFFER_R);
cmdbuf[5] = (u32)body;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
Result PLGLDR__GetVersion(u32 *version)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(8, 0, 0);
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
if (cmdbuf[0] != IPC_MakeHeader(8, 2, 0))
return 0xD900182F;
res = cmdbuf[1];
if (version)
*version = cmdbuf[2];
}
return res;
}
Result PLGLDR__GetPluginPath(char *path)
{
if (path == NULL)
return MAKERESULT(28, 7, 254, 1014); ///< Usage, App, Invalid argument
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(10, 0, 2);
cmdbuf[1] = IPC_Desc_Buffer(255, IPC_BUFFER_RW);
cmdbuf[2] = (u32)path;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
Result PLGLDR__SetRosalinaMenuBlock(bool shouldBlock)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(11, 1, 0);
cmdbuf[1] = (u32)shouldBlock;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
Result PLGLDR__SetSwapSettings(char* swapPath, void* saveFunc, void* loadFunc, void* args)
{
Result res = 0;
const char* trueSwapPath;
if (swapPath) trueSwapPath = swapPath;
else trueSwapPath = "\0";
u32 buf[4] = { 0 };
u32* trueArgs;
if (args) trueArgs = args;
else trueArgs = buf;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(12, 2, 4);
cmdbuf[1] = (saveFunc) ? svcConvertVAToPA(saveFunc, false) | (1 << 31) : 0;
cmdbuf[2] = (loadFunc) ? svcConvertVAToPA(loadFunc, false) | (1 << 31) : 0;
cmdbuf[3] = IPC_Desc_Buffer(4 * sizeof(u32), IPC_BUFFER_R);
cmdbuf[4] = (u32)trueArgs;
cmdbuf[5] = IPC_Desc_Buffer(strlen(trueSwapPath) + 1, IPC_BUFFER_R);
cmdbuf[6] = (u32)trueSwapPath;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
Result PLGLDR__SetExeLoadSettings(void* loadFunc, void* args)
{
Result res = 0;
u32 buf[4] = { 0 };
u32* trueArgs;
if (args) trueArgs = args;
else trueArgs = buf;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(13, 1, 2);
cmdbuf[1] = (loadFunc) ? svcConvertVAToPA(loadFunc, false) | (1 << 31) : 0;
cmdbuf[2] = IPC_Desc_Buffer(4 * sizeof(u32), IPC_BUFFER_R);
cmdbuf[3] = (u32)trueArgs;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
void PLGLDR__SetEventCallback(OnPlgLdrEventCb_t cb)
{
onPlgLdrEventCb = cb;
}
static s32 __ldrex__(s32 *addr)
{
s32 val;
do
val = __ldrex(addr);
while (__strex(addr, val));
return val;
}
static void __strex__(s32 *addr, s32 val)
{
do
__ldrex(addr);
while (__strex(addr, val));
}
void PLGLDR__Status(void)
{
s32 event = __ldrex__(plgEvent); // exclusive read necessary?
if (event <= 0)
return;
if (onPlgLdrEventCb)
onPlgLdrEventCb(event);
__strex__(plgReply, PLG_OK);
__strex__(plgEvent, PLG_WAIT);
if (event < PLG_ABOUT_TO_SWAP)
return;
svcArbitrateAddress(plgLdrArbiter, (u32)plgReply, ARBITRATION_SIGNAL, 1, 0);
if (event == PLG_ABOUT_TO_SWAP)
svcArbitrateAddress(plgLdrArbiter, (u32)plgEvent, ARBITRATION_WAIT_IF_LESS_THAN, PLG_OK, 0);
else if (event == PLG_ABOUT_TO_EXIT)
{
plgLdrExit();
svcExitThread();
}
}