mirror of
https://github.com/azahar-emu/ArticSetupTool
synced 2025-11-06 23:20:00 +01:00
348 lines
7.9 KiB
C
348 lines
7.9 KiB
C
#include <3ds.h>
|
|
#include "plgldr.h"
|
|
#include <string.h>
|
|
#include "csvc.h"
|
|
|
|
static Handle plgLdrHandle;
|
|
static Handle plgLdrArbiter = 0;
|
|
static s32* plgEvent;
|
|
static s32* plgReply;
|
|
static int plgLdrRefCount;
|
|
static bool isN3DS;
|
|
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);
|
|
isN3DS = out != 0;
|
|
if (AtomicPostIncrement(&plgLdrRefCount) == 0)
|
|
res = svcConnectToPort(&plgLdrHandle, "plg:ldr");
|
|
|
|
if (R_SUCCEEDED(res))
|
|
{
|
|
u32 res2 = PLGLDR__GetArbiter();
|
|
if (R_SUCCEEDED(res2) || res2 == 0xE0E01BF4) { // Succeeded or not implemented (citra)
|
|
PluginHeader *header = (PluginHeader *)0x07000000;
|
|
|
|
plgEvent = header->plgldrEvent;
|
|
plgReply = header->plgldrReply;
|
|
} else
|
|
plgLdrExit();
|
|
}
|
|
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) | (((u32)parameters->persistent) << 16);
|
|
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(const char* swapPath, void* encFunc, void* decFunc, void* args)
|
|
{
|
|
Result res = 0;
|
|
|
|
u32* trueArgs;
|
|
u32* cmdbuf = getThreadCommandBuffer();
|
|
u32 buf[0x10] = { 0 };
|
|
|
|
const char* trueSwapPath;
|
|
|
|
if (swapPath) trueSwapPath = swapPath;
|
|
else trueSwapPath = "\0";
|
|
|
|
if (args) trueArgs = args;
|
|
else trueArgs = buf;
|
|
|
|
cmdbuf[0] = IPC_MakeHeader(12, 2, 4);
|
|
cmdbuf[1] = (encFunc) ? (svcConvertVAToPA(encFunc, false) | (1 << 31)) : 0;
|
|
cmdbuf[2] = (decFunc) ? (svcConvertVAToPA(decFunc, false) | (1 << 31)) : 0;
|
|
cmdbuf[3] = IPC_Desc_Buffer(16 * 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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
|
s32 v;
|
|
do
|
|
v = __ldrex(addr);
|
|
while (__strex(addr, val));
|
|
#pragma GCC diagnostic pop
|
|
}
|
|
|
|
void PLGLDR__Status(void)
|
|
{
|
|
}
|
|
|
|
s32 PLGLDR__FetchEvent(void)
|
|
{
|
|
s32 event = __ldrex__(plgEvent); // exclusive read necessary?
|
|
|
|
return event;
|
|
}
|
|
|
|
void PLGLDR__Reply(s32 event)
|
|
{
|
|
__strex__(plgReply, PLG_OK);
|
|
|
|
if (event < PLG_ABOUT_TO_SWAP)
|
|
{
|
|
__strex__(plgEvent, PLG_OK);
|
|
return;
|
|
}
|
|
svcArbitrateAddress(plgLdrArbiter, (u32)plgReply, ARBITRATION_SIGNAL, 1, 0);
|
|
if (event == PLG_ABOUT_TO_SWAP)
|
|
{
|
|
__strex__(plgEvent, PLG_WAIT);
|
|
svcArbitrateAddress(plgLdrArbiter, (u32)plgEvent, ARBITRATION_WAIT_IF_LESS_THAN, PLG_OK, 0);
|
|
}
|
|
else if (event == PLG_ABOUT_TO_EXIT) {
|
|
svcExitThread();
|
|
}
|
|
else
|
|
{
|
|
__strex__(plgEvent, PLG_OK);
|
|
}
|
|
}
|
|
|
|
Result PLGLDR__ClearPluginLoadParameters()
|
|
{
|
|
Result res = 0;
|
|
|
|
u32 *cmdbuf = getThreadCommandBuffer();
|
|
|
|
cmdbuf[0] = IPC_MakeHeader(14, 0, 0);
|
|
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
|
|
{
|
|
res = cmdbuf[1];
|
|
}
|
|
return res;
|
|
}
|