Luma3DS/k11_extension/source/svc/ControlProcess.c

209 lines
7.4 KiB
C
Raw Normal View History

#include "svc/ControlProcess.h"
#include "memory.h"
#include "mmu.h"
#include "synchronization.h"
typedef bool (*ThreadPredicate)(KThread *thread);
// Lock bit has to be different from Rosalina to avoid unintended unlock when using Rosalina menu
static void rescheduleThread(KThread *thread, bool lock)
{
KRecursiveLock__Lock(criticalSectionLock);
u32 oldSchedulingMask = thread->schedulingMask;
if(lock)
thread->schedulingMask |= 0x20;
else
thread->schedulingMask &= ~0x20;
KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, thread, oldSchedulingMask);
KRecursiveLock__Unlock(criticalSectionLock);
}
static void lockThread(KThread *thread)
{
KThread *syncThread = synchronizationMutex->owner;
if(syncThread == NULL || syncThread != thread)
rescheduleThread(thread, true);
}
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);
}
break;
}
case PROCESSOP_SIGNAL_ON_EXIT:
{
*KPROCESS_GET_PTR(process, customFlags) |= SignalOnExit;
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->ownerProcess == process && (thread->schedulingMask & 0x20)
&& (threadPredicate == NULL || threadPredicate(thread)))
rescheduleThread(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
lockThread(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 & 0x20))
{
lockThread(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;
}