Implement plugin loader
This commit is contained in:
@@ -28,11 +28,43 @@
|
||||
#include "utils.h"
|
||||
#include "kernel.h"
|
||||
#include "memory.h"
|
||||
#include "mmu.h"
|
||||
#include "globals.h"
|
||||
|
||||
#define REG_DUMP_SIZE 4 * 23
|
||||
#define CODE_DUMP_SIZE 96
|
||||
|
||||
// Return true if parameters are invalid
|
||||
static bool checkExceptionHandlerValidity(KProcess *process, vu32 *threadLocalStorage)
|
||||
{
|
||||
if (process == NULL)
|
||||
return true;
|
||||
|
||||
u32 stackBottom = threadLocalStorage[0x11];
|
||||
u32 exceptionBuf = threadLocalStorage[0x12];
|
||||
MemoryInfo memInfo;
|
||||
PageInfo pageInfo;
|
||||
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
|
||||
|
||||
u32 perm = KProcessHwInfo__GetAddressUserPerm(hwInfo, threadLocalStorage[0x10]);
|
||||
|
||||
if (stackBottom != 1)
|
||||
{
|
||||
if (KProcessHwInfo__QueryMemory(hwInfo, &memInfo, &pageInfo, (void *)stackBottom)
|
||||
|| (memInfo.permissions & MEMPERM_RW) != MEMPERM_RW)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (exceptionBuf > 1)
|
||||
{
|
||||
if (KProcessHwInfo__QueryMemory(hwInfo, &memInfo, &pageInfo, (void *)exceptionBuf)
|
||||
|| (memInfo.permissions & MEMPERM_RW) != MEMPERM_RW)
|
||||
return true;
|
||||
}
|
||||
|
||||
return (perm & MEMPERM_RX) != MEMPERM_RX;
|
||||
}
|
||||
|
||||
bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
|
||||
{
|
||||
if(CONFIG(DISABLEARM11EXCHANDLERS)) return false;
|
||||
@@ -43,7 +75,7 @@ bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
|
||||
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
|
||||
|
||||
if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0)
|
||||
return false;
|
||||
return checkExceptionHandlerValidity(currentProcess, (vu32 *)thread->threadLocalStorage);
|
||||
|
||||
if(currentProcess != NULL)
|
||||
{
|
||||
@@ -52,7 +84,7 @@ bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
|
||||
|
||||
thread = KPROCESS_GET_RVALUE(currentProcess, mainThread);
|
||||
if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0)
|
||||
return false;
|
||||
return checkExceptionHandlerValidity(currentProcess, thread->threadLocalStorage);
|
||||
|
||||
if(index == 3 && strcmp(codeSetOfProcess(currentProcess)->processName, "menu") == 0 && // workaround a Home Menu bug leading to a dabort
|
||||
regs[0] == 0x3FFF && regs[2] == 0 && regs[5] == 2 && regs[7] == 1)
|
||||
@@ -70,6 +102,7 @@ bool isDataAbortExceptionRangeControlled(u32 spsr, u32 addr)
|
||||
((u32)safecpy <= addr && addr < (u32)safecpy + safecpy_sz)
|
||||
);
|
||||
}
|
||||
|
||||
void fatalExceptionHandlersMain(u32 *registerDump, u32 type, u32 cpuId)
|
||||
{
|
||||
ExceptionDumpHeader dumpHeader;
|
||||
|
||||
@@ -40,8 +40,12 @@ KAutoObject * (*KProcessHandleTable__ToKAutoObject)(KProcessHandleTable *this, H
|
||||
void (*KSynchronizationObject__Signal)(KSynchronizationObject *this, bool isPulse);
|
||||
Result (*WaitSynchronization1)(void *this_unused, KThread *thread, KSynchronizationObject *syncObject, s64 timeout);
|
||||
Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token);
|
||||
Result (*KProcessHwInfo__QueryMemory)(KProcessHwInfo *this, MemoryInfo *memoryInfo, PageInfo *pageInfo, void *address);
|
||||
Result (*KProcessHwInfo__MapProcessMemory)(KProcessHwInfo *this, KProcessHwInfo *other, void *dst, void *src, u32 nbPages);
|
||||
Result (*KProcessHwInfo__UnmapProcessMemory)(KProcessHwInfo *this, void *addr, u32 nbPages);
|
||||
Result (*KProcessHwInfo__CheckVaState)(KProcessHwInfo *hwInfo, u32 va, u32 size, u32 state, u32 perm);
|
||||
Result (*KProcessHwInfo__GetListOfKBlockInfoForVA)(KProcessHwInfo *hwInfo, KLinkedList *list, u32 va, u32 sizeInPage);
|
||||
Result (*KProcessHwInfo__MapListOfKBlockInfo)(KProcessHwInfo *this, u32 va, KLinkedList *list, u32 state, u32 perm, u32 sbz);
|
||||
Result (*KEvent__Clear)(KEvent *this);
|
||||
void (*KObjectMutex__WaitAndAcquire)(KObjectMutex *this);
|
||||
void (*KObjectMutex__ErrorOccured)(void);
|
||||
@@ -49,8 +53,11 @@ void (*KObjectMutex__ErrorOccured)(void);
|
||||
void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 oldSchedulingMask);
|
||||
void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
|
||||
|
||||
void (*KLinkedList_KBlockInfo__Clear)(KLinkedList *list);
|
||||
|
||||
Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
|
||||
void (*SleepThread)(s64 ns);
|
||||
Result (*CreateEvent)(Handle *out, ResetType resetType);
|
||||
Result (*CloseHandle)(Handle handle);
|
||||
Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
|
||||
Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
|
||||
@@ -61,6 +68,7 @@ Result (*SendSyncRequest)(Handle handle);
|
||||
Result (*OpenProcess)(Handle *out, u32 processId);
|
||||
Result (*GetProcessId)(u32 *out, Handle process);
|
||||
Result (*DebugActiveProcess)(Handle *out, u32 processId);
|
||||
Result (*SignalEvent)(Handle event);
|
||||
Result (*UnmapProcessMemory)(Handle processHandle, void *dst, u32 size);
|
||||
Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3);
|
||||
|
||||
@@ -112,3 +120,10 @@ CfwInfo cfwInfo;
|
||||
|
||||
vu32 rosalinaState;
|
||||
bool hasStartedRosalinaNetworkFuncsOnce;
|
||||
|
||||
KLinkedList* KLinkedList__Initialize(KLinkedList *list)
|
||||
{
|
||||
list->size = 0;
|
||||
list->nodes.first = list->nodes.last = (KLinkedListNode *)&list->nodes;
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -96,11 +96,61 @@ void configHook(vu8 *cfgPage)
|
||||
*isDevUnit = true; // enable debug features
|
||||
}
|
||||
|
||||
void KProcessHwInfo__MapL1Section_Hook(void);
|
||||
void KProcessHwInfo__MapL2Section_Hook(void);
|
||||
|
||||
static void installMmuHooks(void)
|
||||
{
|
||||
u32 *mapL1Section = NULL;
|
||||
u32 *mapL2Section = NULL;
|
||||
u32 *off;
|
||||
|
||||
for(off = (u32 *)officialSVCs[0x1F]; *off != 0xE1CD60F0; ++off);
|
||||
off = decodeARMBranch(off + 1);
|
||||
|
||||
for (; *off != 0xE58D5000; ++off);
|
||||
off = decodeARMBranch(off + 1);
|
||||
|
||||
for (; *off != 0xE58DC000; ++off);
|
||||
off = decodeARMBranch(off + 1);
|
||||
for (; *off != 0xE1A0000B; ++off);
|
||||
off = decodeARMBranch(off + 1);
|
||||
for (; *off != 0xE59D2030; ++off);
|
||||
off = decodeARMBranch(off + 1);
|
||||
|
||||
for (; *off != 0xE88D1100; ++off);
|
||||
mapL2Section = (u32 *)PA_FROM_VA_PTR(decodeARMBranch(off + 1));
|
||||
|
||||
do
|
||||
{
|
||||
for (; *off != 0xE58D8000; ++off);
|
||||
u32 *loc = (u32 *)PA_FROM_VA_PTR(decodeARMBranch(++off));
|
||||
if (loc != mapL2Section)
|
||||
mapL1Section = loc;
|
||||
} while (mapL1Section == NULL);
|
||||
|
||||
mapL1Section[1] = 0xE28FE004; // add lr, pc, #4
|
||||
mapL1Section[2] = 0xE51FF004; // ldr pc, [pc, #-4]
|
||||
mapL1Section[3] = (u32)KProcessHwInfo__MapL1Section_Hook;
|
||||
|
||||
mapL2Section[1] = 0xE28FE004; // add lr, pc, #4
|
||||
mapL2Section[2] = 0xE51FF004; // ldr pc, [pc, #-4]
|
||||
mapL2Section[3] = (u32)KProcessHwInfo__MapL2Section_Hook;
|
||||
}
|
||||
|
||||
static void findUsefulSymbols(void)
|
||||
{
|
||||
u32 *off;
|
||||
|
||||
for(off = (u32 *)0xFFFF0000; *off != 0xE1A0D002; off++);
|
||||
// Patch ERRF__DumpException
|
||||
for(off = (u32 *)0xFFFF0000; *off != 0xE1A04005; ++off);
|
||||
++off;
|
||||
*(u32 *)PA_FROM_VA_PTR(off) = makeARMBranch(off, off + 51, false);
|
||||
|
||||
for(; *off != 0xE2100102; ++off);
|
||||
KProcessHwInfo__QueryMemory = (Result (*)(KProcessHwInfo *, MemoryInfo *, PageInfo *, void *))decodeARMBranch(off - 1);
|
||||
|
||||
for(; *off != 0xE1A0D002; off++);
|
||||
off += 3;
|
||||
initFPU = (void (*) (void))off;
|
||||
|
||||
@@ -163,6 +213,18 @@ static void findUsefulSymbols(void)
|
||||
for(off = (u32 *)officialSVCs[0x72]; *off != 0xE2041102; off++);
|
||||
KProcessHwInfo__UnmapProcessMemory = (Result (*)(KProcessHwInfo *, void *, u32))decodeARMBranch(off - 1);
|
||||
|
||||
for (off = (u32 *)officialSVCs[0x70]; *off != 0xE8881200 && *off != 0xE8891900; ++off);
|
||||
for (off = (u32 *)decodeARMBranch(off + 1); *off != 0xE2101102; ++off);
|
||||
KProcessHwInfo__CheckVaState = (Result (*)(KProcessHwInfo *, u32, u32, u32, u32))decodeARMBranch(off - 1);
|
||||
for (; *off != 0xE28D1008; ++off);
|
||||
KProcessHwInfo__GetListOfKBlockInfoForVA = (Result (*)(KProcessHwInfo*, KLinkedList*, u32, u32))decodeARMBranch(off + 1);
|
||||
|
||||
for (; *off != 0xE2000102; ++off);
|
||||
KProcessHwInfo__MapListOfKBlockInfo = (Result (*)(KProcessHwInfo*, u32, KLinkedList*, u32, u32, u32))decodeARMBranch(off - 1);
|
||||
|
||||
for (; *off != 0xE8BD8FF0; ++off);
|
||||
KLinkedList_KBlockInfo__Clear = (void (*)(KLinkedList *))decodeARMBranch(off - 6);
|
||||
|
||||
for(off = (u32 *)officialSVCs[0x7C]; *off != 0x03530000; off++);
|
||||
KObjectMutex__WaitAndAcquire = (void (*)(KObjectMutex *))decodeARMBranch(++off);
|
||||
for(; *off != 0xE320F000; off++);
|
||||
@@ -208,6 +270,7 @@ static void findUsefulSymbols(void)
|
||||
ControlMemory = (Result (*)(u32 *, u32, u32, u32, MemOp, MemPerm, bool))
|
||||
decodeARMBranch((u32 *)officialSVCs[0x01] + 5);
|
||||
SleepThread = (void (*)(s64))officialSVCs[0x0A];
|
||||
CreateEvent = (Result (*)(Handle *, ResetType))decodeARMBranch((u32 *)officialSVCs[0x17] + 3);
|
||||
CloseHandle = (Result (*)(Handle))officialSVCs[0x23];
|
||||
GetHandleInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x29] + 3);
|
||||
GetSystemInfo = (Result (*)(s64 *, s32, s32))decodeARMBranch((u32 *)officialSVCs[0x2A] + 3);
|
||||
@@ -218,6 +281,7 @@ static void findUsefulSymbols(void)
|
||||
OpenProcess = (Result (*)(Handle *, u32))decodeARMBranch((u32 *)officialSVCs[0x33] + 3);
|
||||
GetProcessId = (Result (*)(u32 *, Handle))decodeARMBranch((u32 *)officialSVCs[0x35] + 3);
|
||||
DebugActiveProcess = (Result (*)(Handle *, u32))decodeARMBranch((u32 *)officialSVCs[0x60] + 3);
|
||||
SignalEvent = (Result (*)(Handle event))officialSVCs[0x18];
|
||||
UnmapProcessMemory = (Result (*)(Handle, void *, u32))officialSVCs[0x72];
|
||||
KernelSetState = (Result (*)(u32, u32, u32, u32))((u32 *)officialSVCs[0x7C] + 1);
|
||||
|
||||
@@ -249,6 +313,8 @@ static void findUsefulSymbols(void)
|
||||
invalidateInstructionCacheRange = (void (*)(void *, u32))off2;
|
||||
}
|
||||
}
|
||||
|
||||
installMmuHooks();
|
||||
}
|
||||
|
||||
void main(FcramLayout *layout, KCoreContext *ctxs)
|
||||
|
||||
315
k11_extension/source/mmu.c
Normal file
315
k11_extension/source/mmu.c
Normal file
@@ -0,0 +1,315 @@
|
||||
#include "mmu.h"
|
||||
#include "globals.h"
|
||||
#include "utils.h"
|
||||
|
||||
DescType L1Descriptor__GetType(u32 descriptor)
|
||||
{
|
||||
L1Descriptor pdesc = {descriptor};
|
||||
|
||||
if (pdesc.reserved.bits1_0 == 0b00)
|
||||
return Descriptor_TranslationFault;
|
||||
if (pdesc.reserved.bits1_0 == 0b01)
|
||||
return Descriptor_CoarsePageTable;
|
||||
if (pdesc.reserved.bits1_0 == 0b10)
|
||||
return pdesc.section.bit18 == 0 ? Descriptor_Section : Descriptor_Supersection;
|
||||
return Descriptor_Reserved;
|
||||
}
|
||||
|
||||
DescType L2Descriptor__GetType(u32 descriptor)
|
||||
{
|
||||
L2Descriptor pdesc = {descriptor};
|
||||
|
||||
if (pdesc.translationFault.bits1_0 == 0b01)
|
||||
return Descriptor_LargePage;
|
||||
if (pdesc.smallPage.bit1 == 1)
|
||||
return Descriptor_SmallPage;
|
||||
|
||||
return Descriptor_TranslationFault;
|
||||
}
|
||||
|
||||
void L1MMUTable__RWXForAll(u32 *table)
|
||||
{
|
||||
u32 *tableEnd = table + 1024;
|
||||
|
||||
for (; table != tableEnd; ++table)
|
||||
{
|
||||
L1Descriptor descriptor = {*table};
|
||||
|
||||
switch (L1Descriptor__GetType(descriptor.raw))
|
||||
{
|
||||
case Descriptor_CoarsePageTable:
|
||||
{
|
||||
u32 *l2table = (u32 *)((descriptor.coarsePageTable.addr << 10) - 0x40000000);
|
||||
|
||||
L2MMUTable__RWXForAll(l2table);
|
||||
break;
|
||||
}
|
||||
case Descriptor_Section:
|
||||
{
|
||||
descriptor.section.xn = 0;
|
||||
descriptor.section.apx = 0;
|
||||
descriptor.section.ap = 3;
|
||||
*table = descriptor.raw;
|
||||
break;
|
||||
}
|
||||
case Descriptor_Supersection:
|
||||
{
|
||||
descriptor.supersection.xn = 0;
|
||||
descriptor.supersection.ap = 3;
|
||||
*table = descriptor.raw;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void L2MMUTable__RWXForAll(u32 *table)
|
||||
{
|
||||
u32 *tableEnd = table + 256;
|
||||
|
||||
for (; table != tableEnd; ++table)
|
||||
{
|
||||
L2Descriptor descriptor = {*table};
|
||||
|
||||
switch (L2Descriptor__GetType(descriptor.raw))
|
||||
{
|
||||
case Descriptor_LargePage:
|
||||
{
|
||||
descriptor.largePage.xn = 0;
|
||||
descriptor.largePage.apx = 0;
|
||||
descriptor.largePage.ap = 3;
|
||||
*table = descriptor.raw;
|
||||
break;
|
||||
}
|
||||
case Descriptor_SmallPage:
|
||||
{
|
||||
descriptor.smallPage.xn = 0;
|
||||
descriptor.smallPage.apx = 0;
|
||||
descriptor.smallPage.ap = 3;
|
||||
*table = descriptor.raw;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 L1MMUTable__GetPAFromVA(u32 *table, u32 va)
|
||||
{
|
||||
u32 pa = 0;
|
||||
L1Descriptor descriptor = {table[va >> 20]};
|
||||
|
||||
switch (L1Descriptor__GetType(descriptor.raw))
|
||||
{
|
||||
case Descriptor_CoarsePageTable:
|
||||
{
|
||||
u32 *l2table = (u32 *)((descriptor.coarsePageTable.addr << 10) - 0x40000000);
|
||||
|
||||
pa = L2MMUTable__GetPAFromVA(l2table, va);
|
||||
break;
|
||||
}
|
||||
case Descriptor_Section:
|
||||
{
|
||||
pa = descriptor.section.addr << 20;
|
||||
pa |= (va << 12) >> 12;
|
||||
break;
|
||||
}
|
||||
case Descriptor_Supersection:
|
||||
{
|
||||
pa = descriptor.supersection.addr << 24;
|
||||
pa |= (va << 8) >> 8;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// VA not found
|
||||
break;
|
||||
}
|
||||
|
||||
return pa;
|
||||
}
|
||||
|
||||
u32 L2MMUTable__GetPAFromVA(u32 *table, u32 va)
|
||||
{
|
||||
u32 pa = 0;
|
||||
L2Descriptor descriptor = {table[(va << 12) >> 24]};
|
||||
|
||||
switch(L2Descriptor__GetType(descriptor.raw))
|
||||
{
|
||||
case Descriptor_LargePage:
|
||||
{
|
||||
pa = descriptor.largePage.addr << 16;
|
||||
pa |= va & 0xFFFF;
|
||||
break;
|
||||
}
|
||||
case Descriptor_SmallPage:
|
||||
{
|
||||
pa = descriptor.smallPage.addr << 12;
|
||||
pa |= va & 0xFFF;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return pa;
|
||||
}
|
||||
|
||||
u32 L1MMUTable__GetAddressUserPerm(u32 *table, u32 va)
|
||||
{
|
||||
u32 perm = 0;
|
||||
L1Descriptor descriptor = {table[va >> 20]};
|
||||
|
||||
switch (L1Descriptor__GetType(descriptor.raw))
|
||||
{
|
||||
case Descriptor_CoarsePageTable:
|
||||
{
|
||||
u32 *l2table = (u32 *)((descriptor.coarsePageTable.addr << 10) - 0x40000000);
|
||||
|
||||
perm = L2MMUTable__GetAddressUserPerm(l2table, va);
|
||||
break;
|
||||
}
|
||||
case Descriptor_Section:
|
||||
{
|
||||
perm = descriptor.section.ap >> 1;
|
||||
|
||||
if (perm)
|
||||
{
|
||||
perm |= (!descriptor.section.apx && (descriptor.section.ap & 1)) << 1;
|
||||
perm |= (!descriptor.section.xn) << 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Descriptor_Supersection:
|
||||
{
|
||||
perm = descriptor.supersection.ap >> 1;
|
||||
|
||||
if (perm)
|
||||
{
|
||||
perm |= (descriptor.supersection.ap & 1) << 1;
|
||||
perm |= (!descriptor.supersection.xn) << 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// VA not found
|
||||
break;
|
||||
}
|
||||
|
||||
return perm;
|
||||
}
|
||||
|
||||
u32 L2MMUTable__GetAddressUserPerm(u32 *table, u32 va)
|
||||
{
|
||||
u32 perm = 0;
|
||||
L2Descriptor descriptor = {table[(va << 12) >> 24]};
|
||||
|
||||
switch(L2Descriptor__GetType(descriptor.raw))
|
||||
{
|
||||
case Descriptor_LargePage:
|
||||
{
|
||||
perm = descriptor.largePage.ap >> 1;
|
||||
if (perm)
|
||||
{
|
||||
perm |= (!descriptor.largePage.apx && (descriptor.largePage.ap & 1)) << 1;
|
||||
perm |= (!descriptor.largePage.xn) << 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Descriptor_SmallPage:
|
||||
{
|
||||
perm = descriptor.smallPage.ap >> 1;
|
||||
if (perm)
|
||||
{
|
||||
perm |= (!descriptor.smallPage.apx && (descriptor.smallPage.ap & 1)) << 1;
|
||||
perm |= (!descriptor.smallPage.xn) << 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return perm;
|
||||
}
|
||||
|
||||
void KProcessHwInfo__SetMMUTableToRWX(KProcessHwInfo *hwInfo)
|
||||
{
|
||||
KObjectMutex *mutex = KPROCESSHWINFO_GET_PTR(hwInfo, mutex);
|
||||
u32 *table = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA);
|
||||
|
||||
KObjectMutex__Acquire(mutex);
|
||||
|
||||
L1MMUTable__RWXForAll(table);
|
||||
|
||||
KObjectMutex__Release(mutex);
|
||||
}
|
||||
|
||||
u32 KProcessHwInfo__GetPAFromVA(KProcessHwInfo *hwInfo, u32 va)
|
||||
{
|
||||
KObjectMutex *mutex = KPROCESSHWINFO_GET_PTR(hwInfo, mutex);
|
||||
u32 *table = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA);
|
||||
|
||||
KObjectMutex__Acquire(mutex);
|
||||
|
||||
u32 pa = L1MMUTable__GetPAFromVA(table, va);
|
||||
|
||||
KObjectMutex__Release(mutex);
|
||||
|
||||
return pa;
|
||||
}
|
||||
|
||||
u32 KProcessHwInfo__GetAddressUserPerm(KProcessHwInfo *hwInfo, u32 va)
|
||||
{
|
||||
KObjectMutex *mutex = KPROCESSHWINFO_GET_PTR(hwInfo, mutex);
|
||||
u32 *table = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA);
|
||||
|
||||
KObjectMutex__Acquire(mutex);
|
||||
|
||||
u32 perm = L1MMUTable__GetAddressUserPerm(table, va);
|
||||
|
||||
KObjectMutex__Release(mutex);
|
||||
|
||||
return perm;
|
||||
}
|
||||
|
||||
static union
|
||||
{
|
||||
u32 raw;
|
||||
struct
|
||||
{
|
||||
u32 xn : 1;
|
||||
u32 unkn : 1;
|
||||
u32 cb : 2;
|
||||
u32 ap : 2;
|
||||
u32 tex : 3;
|
||||
u32 apx : 1;
|
||||
u32 s : 1;
|
||||
u32 ng : 1;
|
||||
};
|
||||
} g_rwxState;
|
||||
|
||||
// This function patch the permission when memory is mapped in the mmu table (rwx)
|
||||
KProcessHwInfo *PatchDescriptorAccessControl(KProcessHwInfo *hwInfo, u32 **outState)
|
||||
{
|
||||
KProcess *process = (KProcess *)((u32)hwInfo - 0x1C);
|
||||
u32 state = **outState;
|
||||
u32 flags = KPROCESS_GET_RVALUE(process, customFlags);
|
||||
|
||||
if (flags & SignalOnMemLayoutChanges)
|
||||
*KPROCESS_GET_PTR(process, customFlags) |= MemLayoutChanged;
|
||||
|
||||
if (!(flags & ForceRWXPages))
|
||||
return hwInfo;
|
||||
|
||||
g_rwxState.raw = state;
|
||||
g_rwxState.xn = 0;
|
||||
g_rwxState.ap = 3;
|
||||
g_rwxState.apx = 0;
|
||||
|
||||
*outState = &g_rwxState.raw;
|
||||
|
||||
return hwInfo;
|
||||
}
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "svc/MapProcessMemoryEx.h"
|
||||
#include "svc/UnmapProcessMemoryEx.h"
|
||||
#include "svc/ControlService.h"
|
||||
#include "svc/ControlProcess.h"
|
||||
#include "svc/CopyHandle.h"
|
||||
#include "svc/TranslateHandle.h"
|
||||
|
||||
@@ -59,13 +60,16 @@ void signalSvcEntry(u8 *pageEnd)
|
||||
|
||||
// Since DBGEVENT_SYSCALL_ENTRY is non blocking, we'll cheat using EXCEVENT_UNDEFINED_SYSCALL (debug->svcId is fortunately an u16!)
|
||||
if(debugOfProcess(currentProcess) != NULL && shouldSignalSyscallDebugEvent(currentProcess, svcId))
|
||||
{
|
||||
SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFE, svcId);
|
||||
}
|
||||
}
|
||||
|
||||
void signalSvcReturn(u8 *pageEnd)
|
||||
{
|
||||
u32 svcId = (u32) *(u8 *)(pageEnd - 0xB5);
|
||||
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
|
||||
u32 flags = KPROCESS_GET_RVALUE(currentProcess, customFlags);
|
||||
|
||||
if(svcId == 0xFE)
|
||||
svcId = *(u32 *)(pageEnd - 0x110 + 8 * 4); // r12 ; note: max theortical SVC atm: 0x1FFFFFFF. We don't support catching svcIds >= 0x100 atm either
|
||||
@@ -73,6 +77,13 @@ void signalSvcReturn(u8 *pageEnd)
|
||||
// Since DBGEVENT_SYSCALL_RETURN is non blocking, we'll cheat using EXCEVENT_UNDEFINED_SYSCALL (debug->svcId is fortunately an u16!)
|
||||
if(debugOfProcess(currentProcess) != NULL && shouldSignalSyscallDebugEvent(currentProcess, svcId))
|
||||
SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFF, svcId);
|
||||
|
||||
// Signal if the memory layout of the process changed
|
||||
if (flags & SignalOnMemLayoutChanges && flags & MemLayoutChanged)
|
||||
{
|
||||
*KPROCESS_GET_PTR(currentProcess, customFlags) = flags & ~MemLayoutChanged;
|
||||
SignalEvent(KPROCESS_GET_RVALUE(currentProcess, onMemoryLayoutChangeEvent));
|
||||
}
|
||||
}
|
||||
|
||||
void postprocessSvc(void)
|
||||
@@ -93,10 +104,28 @@ void *svcHook(u8 *pageEnd)
|
||||
u32 svcId = *(u8 *)(pageEnd - 0xB5);
|
||||
if(svcId == 0xFE)
|
||||
svcId = *(u32 *)(pageEnd - 0x110 + 8 * 4); // r12 ; note: max theortical SVC atm: 0x3FFFFFFF. We don't support catching svcIds >= 0x100 atm either
|
||||
|
||||
switch(svcId)
|
||||
{
|
||||
case 0x01:
|
||||
return ControlMemoryHookWrapper;
|
||||
case 0x03: /* svcExitProcess */
|
||||
{
|
||||
// Signal that the process is about to be terminated
|
||||
u32 flags = KPROCESS_GET_RVALUE(currentProcess, customFlags);
|
||||
|
||||
if (flags & SignalOnExit)
|
||||
{
|
||||
SignalEvent(KPROCESS_GET_RVALUE(currentProcess, onProcessExitEvent));
|
||||
|
||||
KEvent* event = (KEvent *)KProcessHandleTable__ToKAutoObject(handleTableOfProcess(currentProcess),
|
||||
KPROCESS_GET_RVALUE(currentProcess, resumeProcessExitEvent));
|
||||
WaitSynchronization1(NULL, currentCoreContext->objectContext.currentThread, (KSynchronizationObject *)event, 10000000000ULL);
|
||||
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event);
|
||||
}
|
||||
return officialSVCs[0x3];
|
||||
}
|
||||
|
||||
case 0x17:
|
||||
if(strcmp(codeSetOfProcess(currentProcess)->processName, "pm") == 0) // only called twice in pm, by the same function
|
||||
{
|
||||
@@ -152,7 +181,7 @@ void *svcHook(u8 *pageEnd)
|
||||
return invalidateEntireInstructionCache;
|
||||
|
||||
case 0xA0:
|
||||
return MapProcessMemoryEx;
|
||||
return MapProcessMemoryExWrapper;
|
||||
case 0xA1:
|
||||
return UnmapProcessMemoryEx;
|
||||
case 0xA2:
|
||||
@@ -164,6 +193,8 @@ void *svcHook(u8 *pageEnd)
|
||||
return CopyHandleWrapper;
|
||||
case 0xB2:
|
||||
return TranslateHandleWrapper;
|
||||
case 0xB3:
|
||||
return ControlProcess;
|
||||
|
||||
default:
|
||||
return (svcId <= 0x7D) ? officialSVCs[svcId] : NULL;
|
||||
|
||||
215
k11_extension/source/svc/ControlProcess.c
Normal file
215
k11_extension/source/svc/ControlProcess.c
Normal file
@@ -0,0 +1,215 @@
|
||||
#include "svc/ControlProcess.h"
|
||||
#include "memory.h"
|
||||
#include "mmu.h"
|
||||
#include "synchronization.h"
|
||||
|
||||
typedef bool (*ThreadPredicate)(KThread *thread);
|
||||
|
||||
void rosalinaLockThread(KThread *thread);
|
||||
void rosalinaRescheduleThread(KThread *thread, bool lock);
|
||||
|
||||
Result ControlProcess(Handle processHandle, ProcessOp op, u32 varg2, u32 varg3)
|
||||
{
|
||||
Result res = 0;
|
||||
KProcess *process;
|
||||
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
|
||||
|
||||
if(processHandle == CUR_PROCESS_HANDLE)
|
||||
{
|
||||
process = currentCoreContext->objectContext.currentProcess;
|
||||
KAutoObject__AddReference((KAutoObject *)process);
|
||||
}
|
||||
else
|
||||
process = KProcessHandleTable__ToKProcess(handleTable, processHandle);
|
||||
|
||||
if(process == NULL)
|
||||
return 0xD8E007F7; // invalid handle
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case PROCESSOP_GET_ALL_HANDLES:
|
||||
{
|
||||
KProcessHandleTable *table = handleTableOfProcess(process);
|
||||
u32 *originalHandleList = (u32 *)varg2;
|
||||
u32 count = 0;
|
||||
u32 searchForToken = varg3;
|
||||
HandleDescriptor *handleDesc = table->handleTable == NULL ? table->internalTable : table->handleTable;
|
||||
|
||||
for (u32 idx = 0; idx < (u32)table->maxHandleCount; ++idx, ++handleDesc)
|
||||
{
|
||||
if (handleDesc->pointer == NULL)
|
||||
continue;
|
||||
|
||||
if (searchForToken)
|
||||
{
|
||||
KClassToken token;
|
||||
|
||||
handleDesc->pointer->vtable->GetClassToken(&token, handleDesc->pointer);
|
||||
if (searchForToken != token.flags)
|
||||
continue;
|
||||
}
|
||||
|
||||
*originalHandleList++ = idx | ((handleDesc->info << 16) >> 1);
|
||||
++count;
|
||||
}
|
||||
res = count;
|
||||
break;
|
||||
}
|
||||
|
||||
case PROCESSOP_SET_MMU_TO_RWX:
|
||||
{
|
||||
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
|
||||
|
||||
*KPROCESS_GET_PTR(process, customFlags) |= ForceRWXPages;
|
||||
KProcessHwInfo__SetMMUTableToRWX(hwInfo);
|
||||
break;
|
||||
}
|
||||
case PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT:
|
||||
{
|
||||
// Only accept current process for this command
|
||||
if (process != currentCoreContext->objectContext.currentProcess)
|
||||
{
|
||||
res = 0xD8E007F7; // invalid handle
|
||||
break;
|
||||
}
|
||||
|
||||
Handle *onMemoryLayoutChangeEvent = KPROCESS_GET_PTR(process, onMemoryLayoutChangeEvent);
|
||||
|
||||
if (*onMemoryLayoutChangeEvent == 0)
|
||||
res = CreateEvent(onMemoryLayoutChangeEvent, RESET_ONESHOT);
|
||||
|
||||
if (res >= 0)
|
||||
{
|
||||
*KPROCESS_GET_PTR(process, customFlags) |= SignalOnMemLayoutChanges;
|
||||
KAutoObject * event = KProcessHandleTable__ToKAutoObject(handleTable, *onMemoryLayoutChangeEvent);
|
||||
|
||||
createHandleForThisProcess((Handle *)varg2, event);
|
||||
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event); ///< This avoid an extra operation on process exit
|
||||
///< Closing the handle in the handle table will destroy the event
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PROCESSOP_GET_ON_EXIT_EVENT:
|
||||
{
|
||||
// Only accept current process for this command
|
||||
if (process != currentCoreContext->objectContext.currentProcess)
|
||||
{
|
||||
res = 0xD8E007F7; // invalid handle
|
||||
break;
|
||||
}
|
||||
|
||||
Handle *onProcessExitEvent = KPROCESS_GET_PTR(process, onProcessExitEvent);
|
||||
Handle *resumeProcessExitEvent = KPROCESS_GET_PTR(process, resumeProcessExitEvent);
|
||||
|
||||
if (*onProcessExitEvent == 0)
|
||||
res = CreateEvent(onProcessExitEvent, RESET_ONESHOT);
|
||||
if (*resumeProcessExitEvent == 0)
|
||||
res |= CreateEvent(resumeProcessExitEvent, RESET_ONESHOT);
|
||||
|
||||
if (res >= 0)
|
||||
{
|
||||
*KPROCESS_GET_PTR(process, customFlags) |= SignalOnExit;
|
||||
KAutoObject * event = KProcessHandleTable__ToKAutoObject(handleTable, *onProcessExitEvent);
|
||||
|
||||
createHandleForThisProcess((Handle *)varg2, event);
|
||||
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event); ///< See higher
|
||||
|
||||
event = KProcessHandleTable__ToKAutoObject(handleTable, *resumeProcessExitEvent);
|
||||
|
||||
createHandleForThisProcess((Handle *)varg3, event);
|
||||
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event); ///< See higher
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PROCESSOP_GET_PA_FROM_VA:
|
||||
{
|
||||
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
|
||||
|
||||
u32 pa = KProcessHwInfo__GetPAFromVA(hwInfo, varg3);
|
||||
*(u32 *)varg2 = pa;
|
||||
|
||||
if (pa == 0)
|
||||
res = 0xE0E01BF5; ///< Invalid address
|
||||
|
||||
break;
|
||||
}
|
||||
case PROCESSOP_SCHEDULE_THREADS:
|
||||
{
|
||||
ThreadPredicate threadPredicate = (ThreadPredicate)varg3;
|
||||
|
||||
KRecursiveLock__Lock(criticalSectionLock);
|
||||
|
||||
if (varg2 == 0) // Unlock
|
||||
{
|
||||
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
|
||||
{
|
||||
KThread *thread = (KThread *)node->key;
|
||||
|
||||
if((thread->schedulingMask & 0xF) == 2) // thread is terminating
|
||||
continue;
|
||||
|
||||
if(thread->schedulingMask & 0x40)
|
||||
rosalinaRescheduleThread(thread, false);
|
||||
}
|
||||
}
|
||||
else // Lock
|
||||
{
|
||||
bool currentThreadsFound = false;
|
||||
|
||||
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
|
||||
{
|
||||
KThread *thread = (KThread *)node->key;
|
||||
|
||||
if(thread->ownerProcess != process
|
||||
|| (threadPredicate != NULL && !threadPredicate(thread)))
|
||||
continue;
|
||||
|
||||
if(thread == coreCtxs[thread->coreId].objectContext.currentThread)
|
||||
currentThreadsFound = true;
|
||||
else
|
||||
rosalinaLockThread(thread);
|
||||
}
|
||||
|
||||
if(currentThreadsFound)
|
||||
{
|
||||
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
|
||||
{
|
||||
KThread *thread = (KThread *)node->key;
|
||||
|
||||
if(thread->ownerProcess != process
|
||||
|| (threadPredicate != NULL && !threadPredicate(thread)))
|
||||
continue;
|
||||
|
||||
if(!(thread->schedulingMask & 0x40))
|
||||
{
|
||||
rosalinaLockThread(thread);
|
||||
KRecursiveLock__Lock(criticalSectionLock);
|
||||
if(thread->coreId != getCurrentCoreID())
|
||||
{
|
||||
u32 cpsr = __get_cpsr();
|
||||
__disable_irq();
|
||||
coreCtxs[thread->coreId].objectContext.currentScheduler->triggerCrossCoreInterrupt = true;
|
||||
currentCoreContext->objectContext.currentScheduler->triggerCrossCoreInterrupt = true;
|
||||
__set_cpsr_cx(cpsr);
|
||||
}
|
||||
KRecursiveLock__Unlock(criticalSectionLock);
|
||||
}
|
||||
}
|
||||
KScheduler__TriggerCrossCoreInterrupt(currentCoreContext->objectContext.currentScheduler);
|
||||
}
|
||||
}
|
||||
|
||||
KRecursiveLock__Unlock(criticalSectionLock);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = 0xF8C007F4;
|
||||
}
|
||||
|
||||
((KAutoObject *)process)->vtable->DecrementReferenceCount((KAutoObject *)process);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -29,11 +29,14 @@
|
||||
|
||||
Result GetHandleInfoHook(s64 *out, Handle handle, u32 type)
|
||||
{
|
||||
if(type == 0x10000) // KDebug and KProcess: get context ID
|
||||
Result res = 0;
|
||||
|
||||
if(type >= 0x10000)
|
||||
{
|
||||
KProcessHwInfo *hwInfo;
|
||||
KProcessHwInfo *hwInfo;
|
||||
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
|
||||
KAutoObject *obj;
|
||||
KAutoObject *obj;
|
||||
|
||||
if(handle == CUR_PROCESS_HANDLE)
|
||||
{
|
||||
obj = (KAutoObject *)(currentCoreContext->objectContext.currentProcess);
|
||||
@@ -45,18 +48,82 @@ Result GetHandleInfoHook(s64 *out, Handle handle, u32 type)
|
||||
if(obj == NULL)
|
||||
return 0xD8E007F7;
|
||||
|
||||
if(strcmp(classNameOfAutoObject(obj), "KDebug") == 0)
|
||||
hwInfo = hwInfoOfProcess(((KDebug *)obj)->owner);
|
||||
else if(strcmp(classNameOfAutoObject(obj), "KProcess") == 0)
|
||||
hwInfo = hwInfoOfProcess((KProcess *)obj);
|
||||
else
|
||||
hwInfo = NULL;
|
||||
switch (type)
|
||||
{
|
||||
case 0x10000: ///< Get ctx id (should probably move it to GetProcessInfo)
|
||||
{
|
||||
if(strcmp(classNameOfAutoObject(obj), "KDebug") == 0)
|
||||
hwInfo = hwInfoOfProcess(((KDebug *)obj)->owner);
|
||||
else if(strcmp(classNameOfAutoObject(obj), "KProcess") == 0)
|
||||
hwInfo = hwInfoOfProcess((KProcess *)obj);
|
||||
else
|
||||
hwInfo = NULL;
|
||||
|
||||
*out = hwInfo != NULL ? KPROCESSHWINFO_GET_RVALUE(hwInfo, contextId) : -1;
|
||||
*out = hwInfo != NULL ? KPROCESSHWINFO_GET_RVALUE(hwInfo, contextId) : -1;
|
||||
break;
|
||||
}
|
||||
case 0x10001: ///< Get referenced object flags (token)
|
||||
{
|
||||
KClassToken token;
|
||||
|
||||
obj->vtable->GetClassToken(&token, obj);
|
||||
*out = token.flags;
|
||||
break;
|
||||
}
|
||||
case 0x10002: ///< Get object owner
|
||||
{
|
||||
Handle hOut;
|
||||
KClassToken token;
|
||||
KProcess * owner = NULL;
|
||||
|
||||
obj->vtable->GetClassToken(&token, obj);
|
||||
switch(token.flags)
|
||||
{
|
||||
case TOKEN_KEVENT:
|
||||
owner = ((KEvent *)obj)->owner;
|
||||
break;
|
||||
case TOKEN_KSEMAPHORE:
|
||||
owner = ((KSemaphore *)obj)->owner;
|
||||
break;
|
||||
case TOKEN_KTIMER:
|
||||
owner = ((KTimer *)obj)->owner;
|
||||
break;
|
||||
case TOKEN_KMUTEX:
|
||||
owner = ((KMutex *)obj)->owner;
|
||||
break;
|
||||
case TOKEN_KDEBUG:
|
||||
owner = ((KDebug *)obj)->owner;
|
||||
break;
|
||||
case TOKEN_KTHREAD:
|
||||
owner = ((KThread *)obj)->ownerProcess;
|
||||
break;
|
||||
case TOKEN_KADDRESSARBITER:
|
||||
owner = ((KAddressArbiter *)obj)->owner;
|
||||
break;
|
||||
case TOKEN_KSHAREDMEMORY:
|
||||
owner = ((KSharedMemory *)obj)->owner;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (owner == NULL)
|
||||
res = 0xD8E007F7;
|
||||
|
||||
res = createHandleForThisProcess(&hOut, (KAutoObject *)owner);
|
||||
*out = hOut;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
res = 0xF8C007F4;
|
||||
break;
|
||||
}
|
||||
|
||||
obj->vtable->DecrementReferenceCount(obj);
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
else
|
||||
return GetHandleInfo(out, handle, type);
|
||||
|
||||
return GetHandleInfo(out, handle, type);
|
||||
}
|
||||
|
||||
@@ -79,6 +79,14 @@ Result GetProcessInfoHook(s64 *out, Handle processHandle, u32 type)
|
||||
*out = ttb & ~((1 << (14 - TTBCR)) - 1);
|
||||
break;
|
||||
}
|
||||
case 0x10009:
|
||||
{
|
||||
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
|
||||
u32 mmusize = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableSize);
|
||||
u32 mmupa = (u32)PA_FROM_VA_PTR(KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA));
|
||||
*out = (s64)(mmusize | ((s64)mmupa << 32));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = 0xD8E007ED; // invalid enum value
|
||||
break;
|
||||
|
||||
@@ -64,6 +64,9 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
|
||||
case 0x101:
|
||||
*out = cfwInfo.rosalinaMenuCombo;
|
||||
break;
|
||||
case 0x102:
|
||||
*out = cfwInfo.rosalinaFlags;
|
||||
break;
|
||||
|
||||
case 0x200: // isRelease
|
||||
*out = cfwInfo.flags & 1;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
static u32 nbEnabled = 0;
|
||||
static u32 maskedPids[MAX_DEBUG];
|
||||
static u32 masks[MAX_DEBUG][8] = {0};
|
||||
static u32 *homeBtnPressed = NULL;
|
||||
|
||||
bool shouldSignalSyscallDebugEvent(KProcess *process, u8 svcId)
|
||||
{
|
||||
@@ -178,6 +179,15 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3)
|
||||
KRecursiveLock__Unlock(&dbgParamsLock);
|
||||
break;
|
||||
}
|
||||
case 0x10007:
|
||||
{
|
||||
// A bit crude but do the job for a simple notification + reboot, nothing sensitive here
|
||||
if (varg1 > 255 && homeBtnPressed == NULL)
|
||||
homeBtnPressed = PA_FROM_VA_PTR((u32 *)varg1);
|
||||
else if (homeBtnPressed != NULL && *homeBtnPressed == 0)
|
||||
*homeBtnPressed = varg1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
res = KernelSetState(type, varg1, varg2, varg3);
|
||||
|
||||
@@ -26,19 +26,61 @@
|
||||
|
||||
#include "svc/MapProcessMemoryEx.h"
|
||||
|
||||
Result MapProcessMemoryEx(Handle processHandle, void *dst, void *src, u32 size)
|
||||
Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size)
|
||||
{
|
||||
Result res = 0;
|
||||
u32 sizeInPage = size >> 12;
|
||||
KLinkedList list;
|
||||
KProcess *srcProcess;
|
||||
KProcess *dstProcess;
|
||||
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
|
||||
KProcessHwInfo *currentHwInfo = hwInfoOfProcess(currentCoreContext->objectContext.currentProcess);
|
||||
KProcess *process = KProcessHandleTable__ToKProcess(handleTable, processHandle);
|
||||
|
||||
if(process == NULL)
|
||||
if (dstProcessHandle == CUR_PROCESS_HANDLE)
|
||||
{
|
||||
dstProcess = currentCoreContext->objectContext.currentProcess;
|
||||
KAutoObject__AddReference((KAutoObject *)dstProcess);
|
||||
}
|
||||
else
|
||||
dstProcess = KProcessHandleTable__ToKProcess(handleTable, dstProcessHandle);
|
||||
|
||||
if (dstProcess == NULL)
|
||||
return 0xD8E007F7;
|
||||
|
||||
Result res = KProcessHwInfo__MapProcessMemory(currentHwInfo, hwInfoOfProcess(process), dst, src, size >> 12);
|
||||
if (srcProcessHandle == CUR_PROCESS_HANDLE)
|
||||
{
|
||||
srcProcess = currentCoreContext->objectContext.currentProcess;
|
||||
KAutoObject__AddReference((KAutoObject *)srcProcess);
|
||||
}
|
||||
else
|
||||
srcProcess = KProcessHandleTable__ToKProcess(handleTable, srcProcessHandle);
|
||||
|
||||
KAutoObject *obj = (KAutoObject *)process;
|
||||
obj->vtable->DecrementReferenceCount(obj);
|
||||
if (srcProcess == NULL)
|
||||
{
|
||||
res = 0xD8E007F7;
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
KLinkedList__Initialize(&list);
|
||||
|
||||
res = KProcessHwInfo__GetListOfKBlockInfoForVA(hwInfoOfProcess(srcProcess), &list, vaSrc, sizeInPage);
|
||||
|
||||
if (res >= 0)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
KLinkedList_KBlockInfo__Clear(&list);
|
||||
|
||||
((KAutoObject *)srcProcess)->vtable->DecrementReferenceCount((KAutoObject *)srcProcess);
|
||||
|
||||
exit1:
|
||||
((KAutoObject *)dstProcess)->vtable->DecrementReferenceCount((KAutoObject *)dstProcess);
|
||||
|
||||
invalidateEntireInstructionCache();
|
||||
flushEntireDataCache();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -29,12 +29,42 @@
|
||||
|
||||
Result UnmapProcessMemoryEx(Handle processHandle, void *dst, u32 size)
|
||||
{
|
||||
if(kernelVersion < SYSTEM_VERSION(2, 37, 0)) // < 6.x
|
||||
return UnmapProcessMemory(processHandle, dst, size); // equivalent when size <= 64MB
|
||||
Result res = 0;
|
||||
u32 sizeInPage = size >> 12;
|
||||
KLinkedList list;
|
||||
KProcess *process;
|
||||
KProcessHwInfo *hwInfo;
|
||||
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
|
||||
|
||||
KProcessHwInfo *currentHwInfo = hwInfoOfProcess(currentCoreContext->objectContext.currentProcess);
|
||||
if (processHandle == CUR_PROCESS_HANDLE)
|
||||
{
|
||||
process = currentCoreContext->objectContext.currentProcess;
|
||||
KAutoObject__AddReference((KAutoObject *)process);
|
||||
}
|
||||
else
|
||||
process = KProcessHandleTable__ToKProcess(handleTable, processHandle);
|
||||
|
||||
Result res = KProcessHwInfo__UnmapProcessMemory(currentHwInfo, dst, size >> 12);
|
||||
if (process == NULL)
|
||||
return 0xD8E007F7;
|
||||
|
||||
hwInfo = hwInfoOfProcess(process);
|
||||
|
||||
KLinkedList__Initialize(&list);
|
||||
|
||||
res = KProcessHwInfo__GetListOfKBlockInfoForVA(hwInfo, &list, (u32)dst, sizeInPage);
|
||||
|
||||
if (res >= 0)
|
||||
{
|
||||
// Check for dst address to be in the right state (0x5806 as we set it with svcMapProcessMemoryEx)
|
||||
res = KProcessHwInfo__CheckVaState(hwInfo, (u32)dst, size, 0x5806, 0);
|
||||
if (res == 0)
|
||||
res = KProcessHwInfo__MapListOfKBlockInfo(hwInfo, (u32)dst, &list, 0, 0, 0);
|
||||
}
|
||||
|
||||
KLinkedList_KBlockInfo__Clear(&list);
|
||||
|
||||
|
||||
((KAutoObject *)process)->vtable->DecrementReferenceCount((KAutoObject *)process);
|
||||
|
||||
invalidateEntireInstructionCache();
|
||||
flushEntireDataCache();
|
||||
|
||||
@@ -84,3 +84,12 @@ ControlMemoryEx:
|
||||
ldr r1, [sp, #12]
|
||||
add sp, #20
|
||||
pop {pc}
|
||||
|
||||
.global MapProcessMemoryExWrapper
|
||||
.type MapProcessMemoryExWrapper, %function
|
||||
MapProcessMemoryExWrapper:
|
||||
push {lr}
|
||||
str r4, [sp, #-4]!
|
||||
bl MapProcessMemoryEx
|
||||
add sp, #4
|
||||
pop {pc}
|
||||
|
||||
@@ -96,6 +96,36 @@ KObjectMutex__Release:
|
||||
blx r12
|
||||
bx lr
|
||||
|
||||
.global KProcessHwInfo__MapL1Section_Hook
|
||||
.type KProcessHwInfo__MapL1Section_Hook, %function
|
||||
KProcessHwInfo__MapL1Section_Hook:
|
||||
@r0 => hwInfo
|
||||
@sp + 0x34 => our ptr to state
|
||||
add r1, sp, #0x34
|
||||
str lr, [sp, #-4]!
|
||||
bl PatchDescriptorAccessControl
|
||||
ldr lr, [sp], #4
|
||||
ldmfd sp, {r0-r4}
|
||||
sub sp, sp, #0x14
|
||||
add r4, sp, #0x48
|
||||
mov r11, #0
|
||||
mov pc, lr
|
||||
|
||||
.global KProcessHwInfo__MapL2Section_Hook
|
||||
.type KProcessHwInfo__MapL2Section_Hook, %function
|
||||
KProcessHwInfo__MapL2Section_Hook:
|
||||
@r0 => hwInfo
|
||||
@sp + 0x34 => our ptr to state
|
||||
add r1, sp, #0x34
|
||||
str lr, [sp, #-4]!
|
||||
bl PatchDescriptorAccessControl
|
||||
ldr lr, [sp], #4
|
||||
ldmfd sp, {r0-r4}
|
||||
sub sp, sp, #0x4C
|
||||
mov r4, r1
|
||||
mov r6, r2
|
||||
mov pc, lr
|
||||
|
||||
.global safecpy
|
||||
.type safecpy, %function
|
||||
safecpy:
|
||||
|
||||
Reference in New Issue
Block a user