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

174 lines
5.2 KiB
C

#include <3ds.h>
#include <string.h>
#include <stdio.h>
#include "plugin.h"
#include "ifile.h"
#include "utils.h"
u32 g_loadExeArgs[0x4];
static inline u32 invertEndianness(u32 val)
{
return ((val & 0xFF) << 24) | ((val & 0xFF00) << 8) | ((val & 0xFF0000) >> 8) | ((val & 0xFF000000) >> 24);
}
Result Check_3gx_Magic(IFile *file)
{
u64 magic;
u64 total;
Result res;
int verDif;
file->pos = 0;
if (R_FAILED((res = IFile_Read(file, &total, &magic, sizeof(u64)))))
return res;
if ((u32)magic != (u32)_3GX_MAGIC) //Invalid file type
return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, RM_LDR, 1);
else if ((verDif = invertEndianness((u32)(magic >> 32)) - invertEndianness((u32)(_3GX_MAGIC >> 32))) != 0) //Invalid plugin version (2 -> outdated plugin; 3 -> outdated loader)
return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, RM_LDR, (verDif < 0) ? 2 : 3);
else return 0;
}
Result Read_3gx_Header(IFile *file, _3gx_Header *header)
{
u64 total;
Result res = 0;
file->pos = 0;
res = IFile_Read(file, &total, header, sizeof(_3gx_Header));
return res;
}
Result Read_3gx_ParseHeader(IFile *file, _3gx_Header *header)
{
u64 total;
char * dst;
Result res = 0;
// Read author
file->pos = (u32)header->infos.authorMsg;
dst = (char *)header + sizeof(_3gx_Header);
res = IFile_Read(file, &total, dst, header->infos.authorLen);
if (R_FAILED(res))
return res;
// Relocate ptr
header->infos.authorMsg = dst;
// Read title
file->pos = (u32)header->infos.titleMsg;
dst += header->infos.authorLen;
res = IFile_Read(file, &total, dst, header->infos.titleLen);
if (R_FAILED(res))
return res;
// Relocate ptr
header->infos.titleMsg = dst;
// Declare other members as null (unused in our case)
header->infos.summaryLen = 0;
header->infos.summaryMsg = NULL;
header->infos.descriptionLen = 0;
header->infos.descriptionMsg = NULL;
// Read targets compatibility
file->pos = (u32)header->targets.titles;
dst += header->infos.titleLen;
dst += 4 - ((u32)dst & 3); // 4 bytes aligned
res = IFile_Read(file, &total, dst, header->targets.count * sizeof(u32));
if (R_FAILED(res))
return res;
// Relocate ptr
header->targets.titles = (u32 *)dst;
return res;
}
Result Read_3gx_LoadSegments(IFile *file, _3gx_Header *header, void *dst)
{
u32 size;
u64 total;
Result res = 0;
_3gx_Executable *exeHdr = &header->executable;
PluginLoaderContext *ctx = &PluginLoaderCtx;
file->pos = exeHdr->codeOffset;
size = exeHdr->codeSize + exeHdr->rodataSize + exeHdr->dataSize;
res = IFile_Read(file, &total, dst, size);
if (!res && !ctx->isExeLoadFunctionset) return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, RM_LDR, RD_NO_DATA);
u32 checksum = 0;
if (!res) checksum = loadExeFunc(dst, dst + size, g_loadExeArgs);
if (!res && checksum != ctx->exeLoadChecksum) res = MAKERESULT(RL_PERMANENT, RS_INVALIDARG, RM_LDR, RD_INVALID_ADDRESS);
Reset_3gx_LoadParams();
return res;
}
Result Read_3gx_EmbeddedPayloads(IFile *file, _3gx_Header *header)
{
u32 tempBuff[32];
u32 tempBuff2[4];
u64 total;
Result res = 0;
PluginLoaderContext *ctx = &PluginLoaderCtx;
if (header->infos.embeddedExeLoadFunc) {
file->pos = header->executable.exeLoadFuncOffset;
res = IFile_Read(file, &total, tempBuff, sizeof(tempBuff));
memcpy(tempBuff2, header->infos.builtInLoadExeArgs, sizeof(tempBuff2));
if (!res) res = Set_3gx_LoadParams(tempBuff, tempBuff2);
if (!res) ctx->isExeLoadFunctionset = true;
}
if (!res && header->infos.embeddedSwapSaveLoadFunc) {
file->pos = header->executable.swapSaveFuncOffset;
res = IFile_Read(file, &total, tempBuff, sizeof(tempBuff));
memcpy(tempBuff2, header->infos.builtInSwapSaveLoadArgs, sizeof(tempBuff2));
if (!res) res = MemoryBlock__SetSwapSettings(tempBuff, false, tempBuff2);
file->pos = header->executable.swapLoadFuncOffset;
if (!res) res = IFile_Read(file, &total, tempBuff, sizeof(tempBuff));
if (!res) res = MemoryBlock__SetSwapSettings(tempBuff, true, tempBuff2);
if (!res) ctx->isSwapFunctionset = true;
}
return res;
}
Result Set_3gx_LoadParams(u32* loadFunc, u32* params)
{
u32* loadExeFuncAddr = PA_FROM_VA_PTR((u32)loadExeFunc); //Bypass mem permissions
memcpy(g_loadExeArgs, params, sizeof(g_loadExeArgs));
int i = 0;
for (; i < 32 && loadFunc[i] != 0xE320F000; i++)
loadExeFuncAddr[i] = loadFunc[i];
if (i >= 32) {
return -1;
}
return 0;
}
void Reset_3gx_LoadParams(void)
{
PluginLoaderContext *ctx = &PluginLoaderCtx;
u32* loadExeFuncAddr = PA_FROM_VA_PTR((u32)loadExeFunc); //Bypass mem permissions
memset(g_loadExeArgs, 0, sizeof(g_loadExeArgs));
loadExeFuncAddr[0] = 0xE12FFF1E; // BX LR
for (int i = 1; i < 32; i++) {
loadExeFuncAddr[i] = 0xE320F000; // NOP
}
ctx->isExeLoadFunctionset = false;
svcInvalidateEntireInstructionCache();
}