Last active
November 4, 2024 23:44
-
-
Save TuxSH/f1f270710ed84576823fd1da348acb38 to your computer and use it in GitHub Desktop.
Complete 3DS kernel decompilation (11.14-latest N3DS Kernel11, with labels for all symbols, and comments)
This file has been truncated, but you can view the full file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* This file was generated by the Hex-Rays decompiler. | |
Copyright (c) 2007-2020 Hex-Rays <[email protected]> | |
Detected compiler: GNU C++ | |
*/ | |
#include <defs.h> | |
//------------------------------------------------------------------------- | |
// Function declarations | |
void crt0::Cpu0GetInitSpValues(); | |
void crt0::Cpu1GetInitSpValues(); | |
void crt0::Cpu2GetInitSpValues(); | |
void crt0::Cpu3GetInitSpValues(); | |
void __noreturn _start(void); | |
void __fastcall crt0::CoreSync(s32 coreId); | |
void crt0::SetVfpAccessibleToUser(void); | |
void __fastcall crt0::WaitCycles(u32 numCycles); | |
void crt0::SetArm11ControlRegs(void); | |
void __noreturn crt0::Core23Ep(void); | |
void __fastcall crt0::PrepareTranslationTables(s32 coreId); | |
u8 *crt0::FetchArm9Info(void); | |
void __fastcall crt0::memmove(void *dst, const void *src, u32 size); | |
void _libc_init_array(void); | |
void _sti___27_KCacheMaintenanceHelper_cpp(void); | |
void _sti___15_KDmaChannel_cpp(void); | |
void _sti___10_KDebug_cpp(void); | |
void _sti___10_KEvent_cpp(void); | |
void _sti___11_KTimer_cpp(void); | |
void _sti___10_Kernel_cpp(void); | |
void _sti___11_KThread_cpp(void); | |
void _sti___26_KVfpRegisterDumpHelper_cpp(void); | |
void _sti___12_KProcess_cpp(void); | |
void _sti___15_KLinkedList_cpp(void); | |
void _sti___31_KPerformanceCounterManager_cpp(void); | |
void _sti___9_Sleep_cpp(void); | |
void _sti___15_KDmaManager_cpp(void); | |
void _sti___27_KObjectAllocatorAdapter_cpp(void); | |
int __fastcall _aeabi_atexit_veneer(void *object, void (__fastcall *destroyer)(void *), void *dso_handle); | |
int __fastcall _cxa_guard_release_veneer(int *guard); | |
void *__fastcall _aeabi_vec_ctor_nocookie_nodtor_from_arm(void *user_array, void *(__fastcall *constructor)(void *), u32 element_size, u32 element_count); | |
KObjectContainer *__fastcall KObjectContainer::KObjectContainer(KObjectContainer *this); | |
void _sti___21_KPxiBufferManager_cpp(void); | |
void _sti___14_KFiqHelper_cpp(void); | |
void _sti___20_KSlabHeapAdapter_cpp(void); | |
void _sti___29_KPerformanceControlHelper_cpp(void); | |
void crt0::CopyAndJumpToCore0Stub(void); | |
// void __usercall __noreturn crt0::Core0StubData(); | |
void __noreturn crt0::CopyAndJumpToCore1Stub(void); | |
// void __usercall __noreturn crt0::Core1StubData(s32 coreId@<R2>); | |
void __fastcall crt0::CopyFinalStub(const void *start, const void *end, void *dst); | |
void __fastcall crt0::StopExtraCoresAndJump(s32 coreId); | |
// void __usercall __noreturn crt0::Core0Stub(); | |
// void __usercall __noreturn crt0::Core1FinalStub(s32 coreId@<R2>); | |
int __fastcall _aeabi_vec_dtor(int, void (__fastcall *)(int), int, int); | |
void __noreturn HandleFiqException(); | |
Result __fastcall KScheduler::Intialize(KScheduler *this, s32 coreId, KThread *idleThread); | |
void __fastcall KScheduler::Enable(KScheduler *this); | |
void CreateKernelDiagnosticTable(void); | |
void InitSharedKernelConfigPage(void); | |
void __fastcall KCoreLocalContext::InitializeCurrent(s32 coreId); | |
void AllocateSharedConfigPages(void); | |
void __fastcall KLevel2TranslationTableAllocator::Initialize(u32 cpuId); | |
void __fastcall KHardwareTimer::Initialize(KHardwareTimer *this, s32 coreId); | |
Result KDebug::InitializeScheduledInOutState(void); | |
void __fastcall KThread::SetIdlePriority(KThread *this); | |
void __fastcall __noreturn HandlePrefetchAbortException(int a1, int a2, int a3, int a4, int a5); | |
void __fastcall HandleDataAbortException(int, int, int, int, int); | |
char *__fastcall HandleIrqException(int a1, int a2, int *a3, int a4, int a5); | |
void __fastcall __noreturn HandleSvcException(int, int, int, int, int, int, __int16); | |
int __fastcall HandleUndefinedInstructionException(int result, int, int, int, _DWORD *); | |
KScheduler *__fastcall KScheduler::KScheduler(KScheduler *this); | |
void __fastcall __noreturn KWorkerTaskManager::ThreadFunction(KWorkerTaskManager *this); | |
void __fastcall __noreturn KInterruptTaskManager::ThreadFunction(KInterruptTaskManager *this); | |
Result __fastcall KThread::InitializeCriticalKernelThread(KThread *this, void *ep, void *arg); | |
void KDmaController::Initialize(void); | |
void __fastcall KDmaController::EnableInterrupt(s8 channelId); | |
Result __fastcall KVfpRegisterDumpHelper::BindInterrupt(s32 coreId); | |
Result __fastcall KTlbMaintenanceHelper::BindInterrupt(s32 coreId); | |
Result __fastcall KPerformanceCounterControlHelper::BindInterrupt(s32 coreId); | |
void __fastcall KPageTable::InvalidateEntireInstructionCacheLocal(); | |
u32 __fastcall InitialProcess::GetCxiSize(InitialProcess *this); | |
void __fastcall AtomicBoolStore(AtomicBool *this, bool value); | |
void __fastcall __noreturn DispatchKernelExceptionWithRegdump(int, int, int, int, int); | |
void __fastcall LzssDecompress(u8 *fileEnd); | |
Result __fastcall SvcAcceptSession(int, Handle); | |
Result __fastcall SvcConnectToPort(int a1, const char *a2); | |
Result __fastcall SvcControlMemory(u8 op, u32, u32, u32); | |
Result __fastcall SvcControlProcessMemory(Handle a1, u32 a2, u32 a3, u32 a4); | |
Result SvcCreateAddressArbiter(); | |
Result __fastcall SvcCreateCodeSet(u32 dataPtr, CodeSetInfo *, u32, u32); | |
Result __fastcall SvcCreateEvent(int a1, ResetType a2); | |
Result __fastcall SvcCreateMemoryBlock(u32 othersPerms, u32, u32, u32); | |
Result __fastcall SvcCreateMutex(int a1, BOOL a2); | |
Result __fastcall SvcCreatePort(int, int, const char *, s32); | |
Result __fastcall SvcCreateProcess(int, Handle, u32 *, s32); | |
Result SvcCreateResourceLimit(); | |
Result SvcCreateSession(); | |
Result __fastcall SvcCreateSessionToPort(int, Handle); | |
Result __fastcall SvcDebugActiveProcess(int a1, u32 a2); | |
Result __fastcall SvcDuplicateHandle(int a1, Handle a2); | |
Result __fastcall SvcGetDebugThreadParam(DebugThreadParameter param, int a2, Handle a3, u32 a4); | |
Result __fastcall SvcGetHandleInfo(int, Handle, s32); | |
Result __fastcall SvcGetProcessId(int a1, Handle a2); | |
Result __fastcall SvcGetProcessIdOfThread(int a1, Handle a2); | |
Result __fastcall SvcGetProcessIdealProcessor(int a1, Handle a2); | |
Result __fastcall SvcGetProcessInfo(int, Handle, s32); | |
Result __fastcall SvcGetProcessList(int a1, u32 *a2, s32 a3); | |
Result __fastcall SvcGetResourceLimit(int a1, Handle a2); | |
Result __fastcall SvcGetSystemInfo(int a1, s32 a2, s32 a3); | |
Result __fastcall SvcGetThreadIdealProcessor(int a1, Handle a2); | |
Result __fastcall SvcGetThreadInfo(int a1, Handle a2, s32 a3); | |
Result __fastcall SvcGetThreadList(int a1, u32 *a2, s32 a3, Handle a4); | |
Result __fastcall SvcGetThreadPriority(int a1, Handle a2); | |
Result Svc0x74_CodeSetRelated_stubbed(); | |
Result __fastcall SvcOpenProcess(int, u32); | |
Result __fastcall SvcOpenThread(int a1, Handle a2, u32 a3); | |
Result __fastcall SvcQueryDebugProcessMemory(int a1, int a2, Handle a3, u32 a4); | |
Result __fastcall SvcQueryMemory(int a1, int a2, u32 a3); | |
Result __fastcall SvcQueryProcessMemory(int a1, int a2, Handle a3, u32 a4); | |
Result __fastcall SvcReplyAndReceive(int a1, Handle *a2, s32 a3, Handle a4); | |
Result __fastcall SvcReplyAndReceive1(int a1, Handle *a2, s32 a3, Handle a4); | |
Result __fastcall SvcReplyAndReceive2(int a1, Handle *a2, s32 a3, Handle a4); | |
Result __fastcall SvcReplyAndReceive3(int a1, Handle *a2, s32 a3, Handle a4); | |
Result __fastcall SvcReplyAndReceive4(int a1, Handle *a2, s32 a3, Handle a4); | |
Result __fastcall SvcSignalAndWait(bool waitAll, Handle a2, Handle *a3, s32 a4); | |
KThreadIntrusiveList *__fastcall KThreadIntrusiveList::KThreadIntrusiveList(KThreadIntrusiveList *this); | |
void __fastcall KAffinityMask::Normalize(KAffinityMask *dstAffMask, KAffinityMask *this, u8 numCores); | |
void PostSvcDpcHandler(void); | |
Result __fastcall SvcClearEvent(Handle eventHandle); | |
void __noreturn SvcExitThread(void); | |
Result __fastcall SvcCloseHandle(Handle handle); | |
s64 SvcGetSystemTick(void); | |
int __fastcall SvcSetWifiEnabled(bool a1); | |
Result __fastcall SvcMapMemoryBlock(Handle sharedMemHandle, u32 addr, u32 myPerms, u32 othersPerms); | |
Result __fastcall SvcSendSyncRequest(Handle clientSessionHandle); | |
void __fastcall SvcStopPointOrInvalidId(u32 svcId); | |
Result __fastcall SvcGetThreadContext(ThreadContext *ctx, Handle threadHandle); | |
Result __fastcall SvcFlushCodeSegment(u32 addr, u32 size); | |
Result __fastcall SvcSendSyncRequest1(Handle clientSessionHandle); | |
Result __fastcall SvcSendSyncRequest2(Handle clientSessionHandle); | |
Result __fastcall SvcSendSyncRequest3(Handle clientSessionHandle); | |
Result __fastcall SvcSendSyncRequest4(Handle clientSessionHandle); | |
Result __fastcall SvcTerminateProcess(Handle processHandle); | |
Result __fastcall SvcUnmapMemoryBlock(Handle handle, u32 addr); | |
Result __fastcall SvcUnmapProcessMemory(Handle processHandle, u32 addr, u32 size); | |
Result __fastcall SvcBreakDebugProcess(Handle debugHandle); | |
Result __fastcall SvcOutputDebugString(u32 addr, u32 size); | |
Result __fastcall SvcReadDebugProcessMemory(u32 dstAddr, Handle debugHandle, u32 addr, u32 size); | |
Result __fastcall SvcContinueDebugEvent(Handle debugHandle, DebugFlags debugFlags); | |
Result __fastcall SvcWriteDebugProcessMemory(Handle debugHandle, u32 addr, u32 dstAddr, u32 size); | |
Result __fastcall SvcSetProcessResourceLimits(Handle processHandle, Handle resLimitHandle); | |
Result __fastcall SvcGetProcessDebugEvent(DebugEventInfo *outDebugEventInfo, Handle debugHandle); | |
Result __fastcall SvcWaitSynchronization1(Handle handle, s64 timeout); | |
Result __fastcall SvcSetGpuProt(bool allowSystem); | |
Result __fastcall SvcGetDebugThreadContext(ThreadContext *outThreadContext, Handle debugHandle, u32 tid, ThreadContextControlFlags flags); | |
Result __fastcall SvcGetThreadAffinityMask(u8 *outAffinityMask, Handle threadHandle, s32 processorCount); | |
Result __fastcall SvcSetDebugThreadContext(Handle debugHandle, u32 tid, const ThreadContext *threadContext, ThreadContextControlFlags flags); | |
Result __fastcall SvcSetHardwareBreakPoint(s32 regId, u32 cr, u32 vr); | |
Result __fastcall SvcSetThreadAffinityMask(Handle threadHandle, u8 *affinityMask, s32 processorCount); | |
Result __fastcall SvcStoreProcessDataCache(Handle a1, u32 a2, u32 a3); | |
Result __fastcall SvcTerminateDebugProcess(Handle debugHandle); | |
Result __fastcall SvcGetProcessAffinityMask(u8 *outAffMask, Handle processHandle, s32 coreCount); | |
Result __fastcall SvcSetProcessAffinityMask(Handle processHandle, const u8 *affinityMask, s32 numCores); | |
Result __fastcall SvcSetThreadIdealProcessor(Handle threadHandle, s32 idealProcessor); | |
Result __fastcall SvcSetProcessIdealProcessor(Handle processHandle, s32 idealProcessor); | |
s32 SvcGetCurrentProcessorNumber(void); | |
Result __fastcall SvcInvalidateProcessDataCache(Handle, u32, u32); | |
Result __fastcall SvcGetResourceLimitLimitValues(s64 *outLimitValues, Handle reslimitHandle, const ResourceLimitType *names, s32 nameCount); | |
Result __fastcall SvcSetResourceLimitLimitValues(Handle reslimitHandle, const ResourceLimitType *names, const s64 *values, s32 count); | |
Result __fastcall SvcGetResourceLimitCurrentValues(s64 *outCurrentValues, Handle reslimitHandle, const ResourceLimitType *names, s32 nameCount); | |
Result __fastcall SvcBreak(UserBreakType breakReason, u32 croInfoAddr, u32 croInfoSize); | |
void __fastcall IrqHandlerImpl(BOOL user); | |
void __fastcall DumpVfpSprsForUserDispatch(ERRF_ExceptionInfo *info); | |
void __fastcall KScheduler::TrySwitchingToInterruptTaskMgrThread(KScheduler *this); | |
KHandleTable *__fastcall KHandleTable::KHandleTable(KHandleTable *this); | |
Result __fastcall KSharedMemory::Map(KSharedMemory *this, KProcessPageTable *dstPgTable, u32 dstAddr, KProcess *dstProcess, KMemoryPermission myPerms, KMemoryPermission othersPerms); | |
Result __fastcall KSharedMemory::Unmap(KSharedMemory *this, KProcessPageTable *dstPgTable, u32 addr, KProcess *dstProcess); | |
Result __fastcall KClientSession::SendSyncRequest(KClientSession *this, KThread *thread); | |
Result __fastcall KSynchronization::WaitSynchronization1(KSynchronization *this, KThread *thread, KSynchronizationObject *obj, s64 timeout); | |
void __fastcall KThread::EnableExclusiveVfp(KThread *this); | |
void __fastcall KVfpRegisterDumpHelper::DumpAndDisableVfpRegsForThread(KThread *thread, s32 coreId); | |
void __fastcall SetWifiEnabled(bool enable); | |
void __fastcall SetGpuProt(BOOL allowSystem); | |
Result __fastcall CreatePort(Handle *outSessionPortHandle, Handle *outClientPortHandle, const char *name, s32 maxSessionCount); | |
Result __fastcall OpenThread(Handle *outThreadHandle, Handle processHandle, u32 threadId); | |
Result __fastcall CreateEvent(Handle *outEventHandle, ResetType resetType); | |
Result __fastcall CreateMutex(Handle *outMutexHandle, BOOL initiallyLocked); | |
Result Svc0x74Impl_CodeSetRelated_Stubbed(Handle *codesetHandleMaybe, ...); | |
Result __fastcall OpenProcess(Handle *outProcessHandle, u32 pid); | |
Result __fastcall QueryMemory(MemoryInfo *outMemInfo, u32 *outPgInfo, u32 addr); | |
Result __fastcall CreateThread(Handle *outThreadHandle, u32 ep, u32 arg, u32 stackTop, s32 priority, s32 processorId); | |
Result __fastcall GetProcessId(u32 *outPid, Handle processHandle); | |
Result __fastcall AcceptSession(Handle *outServerSessionHandle, Handle serverPortHandle); | |
Result __fastcall ConnectToPort(Handle *outClientSessionHandle, const char *name); | |
Result __fastcall ControlMemory(u32 *outAddr, u32 addr0, u32 addr1, u32 size, u8 op, u32 perms); | |
Result __fastcall CreateCodeSet(Handle *outHandle, CodeSetInfo *codeSetInfo, u32 textPtr, u32 rodataPtr, u32 dataPtr); | |
Result __fastcall CreateProcess(Handle *outProcessHandle, Handle codeSetHandle, u32 *kernelCaps, s32 numKernelCaps); | |
Result __fastcall CreateSession(Handle *outServerSessionHandle, Handle *outClientSessionHandle); | |
Result __fastcall GetHandleInfo(s64 *out, Handle handle, s32 type); | |
Result __fastcall GetSystemInfo(s64 *out, s32 type, s32 subType); | |
Result __fastcall GetThreadInfo(s64 *outValue, Handle threadHandle, s32 type); | |
Result __fastcall GetThreadList(s32 *outNumThreads, u32 *outTids, s32 maxNumThreads, Handle processHandle); | |
Result __fastcall SignalAndWait(s32 *idx, Handle signal, Handle *handles, s32 numHandles, bool waitAll, s64 timeout); | |
Result __fastcall GetProcessInfo(s64 *outValue, Handle processHandle, s32 type); | |
Result __fastcall GetProcessList(s32 *outNumProcesses, u32 *outPids, s32 maxNumProcesses); | |
Result __fastcall DuplicateHandle(Handle *outHandle, Handle handle); | |
Result __fastcall ReplyAndReceive(s32 *outIdx, Handle *handles, s32 numHandles, Handle replyTargetHandle); | |
Result __fastcall GetResourceLimit(Handle *outReslimit, Handle processHandle); | |
Result __fastcall ReplyAndReceive1(s32 *outIdx, Handle *handles, s32 numHandles, Handle replyTargetHandle); | |
Result __fastcall ReplyAndReceive2(s32 *outIdx, Handle *handles, s32 numHandles, Handle replyTargetHandle); | |
Result __fastcall ReplyAndReceive3(s32 *outIdx, Handle *handles, s32 numHandles, Handle replyTargetHandle); | |
Result __fastcall ReplyAndReceive4(s32 *outIdx, Handle *handles, s32 numHandles, Handle replyTargetHandle); | |
Result __fastcall CreateMemoryBlock(Handle *outSharedMemHandle, u32 addr, u32 size, u32 ownerPerms, u32 othersPerms); | |
Result __fastcall GetThreadPriority(s32 *outPriority, Handle threadHandle); | |
Result __fastcall DebugActiveProcess(Handle *outHandle, u32 pid); | |
Result __fastcall QueryProcessMemory(MemoryInfo *outMemInfo, u32 *outPgInfo, Handle processHandle, u32 addr); | |
Result __fastcall CreateResourceLimit(Handle *outReslimitHandle); | |
Result __fastcall CreateSessionToPort(Handle *outClientSessionHandle, Handle clientPortHandle); | |
Result __fastcall GetDebugThreadParam(s64 *out1, s32 *out2, Handle debugHandle, u32 tid, DebugThreadParameter param); | |
Result __fastcall CreateAddressArbiter(Handle *outArbiterHandle); | |
Result __fastcall GetProcessIdOfThread(u32 *outPid, Handle threadHandle); | |
Result __fastcall GetThreadIdealProcessor(s32 *outIdealProcessor, Handle threadHandle); | |
Result __fastcall QueryDebugProcessMemory(MemoryInfo *outMemInfo, u32 *outPgInfo, Handle debugHandle, u32 addr); | |
Result __fastcall ControlProcessMemory(Handle processHandle, u32 addr0, u32 addr1, u32 size, u32 op, u32 perms); | |
Result __fastcall GetProcessIdealProcessor(s32 *outIdealProcessor, Handle processHandle); | |
Result __fastcall KCacheOperator::OperateOnProcessCache(KCacheOperator *this, Handle processHandle, u32 addr, u32 size); | |
Result __fastcall KProcessPageTable::UnmapProcessMemory(KProcessPageTable *this, u32 addr, u32 numPages); | |
void __fastcall SetResourceLimitLimitValues(SetResourceLimitLimitValuesArgs *args, ResourceLimitKvPair *pairs); | |
Result __fastcall Run(Handle processHandle, const StartupInfo *info); | |
Result __fastcall KEvent::Clear(KEvent *this); | |
Result __fastcall KMutex::Unlock(KMutex *this, KThread *thread); | |
bool __fastcall KInterruptManager::HandleIncomingInterrupt(KInterruptManager *this); | |
Result __fastcall SetHardwareBreakpoint(s32 regId, u32 cr, u32 vr); | |
Result __fastcall KDebug::ReadProcessMemory(KDebug *this, u32 dstAddr, u32 addr, u32 size); | |
Result __fastcall KDebug::WriteProcessMemory(KDebug *this, u32 addr, u32 dstAddr, u32 size); | |
Result __fastcall KDebug::BreakProcess(KDebug *this); | |
Result __fastcall KDebug::Continue(KDebug *this, DebugFlags debugFlags); | |
Result __fastcall KDebug::EraseFirstEventInfoToFetchNode(KDebug *this); | |
Result __fastcall KDebug::GetPausedThreadContextById(KDebug *this, ThreadContext *outThreadContext, u32 tid, ThreadContextControlFlags flags); | |
BOOL __fastcall KDebug::NeedsContinue(KDebug *this); | |
Result __fastcall KDebug::SetPausedThreadContextById(KDebug *this, ThreadContext *threadContext, u32 tid, ThreadContextControlFlags flags); | |
Result __fastcall KDebug::TerminateProcess(KDebug *this); | |
Result __fastcall BreakImpl(UserBreakType breakReason, u32 croInfoAddr, u32 croInfoSize); | |
void __fastcall KDebug::ProcessEventInfo(KDebug *this, DebugEventType type, KEventInfo *info); | |
KEventInfo *__fastcall KDebug::GetFirstEventInfoToFetch(KDebug *this); | |
KCodeSet *__fastcall KCodeSet::KCodeSet(KCodeSet *this); | |
Result __fastcall KProcess::UnbindUserInterruptEventChecked(KProcess *this, KInterruptEvent *interruptEvent, u32 interruptId); | |
BOOL __fastcall KProcess::IsDebugged(KProcess *this); | |
Result __fastcall KProcess::SetResourceLimits(KProcess *this, KResourceLimit *reslimit); | |
Result __fastcall KProcess::Run(KProcess *this, u32 mainThreadPrio, u32 mainThreadStackSize); | |
void __fastcall KDebug::DoWorkerTask(KWorkerTask *__shifted(KDebug,0x14) this); | |
Result __fastcall KProcess::TerminateOtherProcess(KProcess *this); | |
void __fastcall SetEightBytesTo1(bool *statusArray, bool isFree); | |
KFiqState __fastcall KFiqState::CompareExchangeStrong(KFiqState *this, KFiqState oldVal, KFiqState newVal); | |
void __fastcall KFiqState::Set(KFiqState *this, KFiqState newState); | |
KInterruptEvent *__fastcall KHandleTable::ConvertToInterruptEvent(KHandleTable *this, Handle handle); | |
void __fastcall KThreadContext::LoadVfp(KThreadContext *ctx); | |
bool __fastcall KScheduler::RemoveTerminatingThread(KScheduler *this, KThread *thread); | |
Result __fastcall KScheduler::ChangeAppPreemptionMode(u32 newMode); | |
void __fastcall KScheduler::YieldCurrentThread(KScheduler *this); | |
void __fastcall KScheduler::InitializeNewThread(KScheduler *this, KThread *thread); | |
void __fastcall KSemaphore::Initialize(KSemaphore *this, KProcess *ownerProcess, s32 initialCount, s32 maxCount); | |
Result __fastcall KClientPort::CreateSession(KClientPort *this, KClientSession **outClientSessionPtr); | |
void __fastcall KDmaManager::AbortAll(KDmaManager *this); | |
KAutoObject *__fastcall KObjectName::FindObject(const char *name); | |
Result __fastcall KObjectName::RegisterObject(KAutoObject *obj, const char *name); | |
KServerSession *__fastcall KServerPort::AcceptSession(KServerPort *this); | |
void __fastcall KCodeSegment::EnsureCacheCoherencyForCode(KCodeSegment *this); | |
KCodeSegment *__fastcall KCodeSegment::KCodeSegment(KCodeSegment *this); | |
void __fastcall KProcess::ChangeAffinityMask(u8 *newAffMask, u8 affMask, bool add); | |
void __fastcall KAffinityMask::MakeAllCoresMask(KAffinityMask *result); | |
Result __fastcall KSharedMemory::Initialize(KSharedMemory *this, KProcess *ownerProcess, u32 addr, u32 size, u32 ownerPerms, u32 othersPerms); | |
KSharedMemory *__fastcall KSharedMemory::KSharedMemory(KSharedMemory *__hidden this); | |
s32 __fastcall KResourceLimit::GetCurrentValue(KResourceLimit *this, ResourceLimitType type); | |
KCpuTimeLimit *__fastcall KResourceLimit::GetTimeLimit(KResourceLimit *this); | |
Result __fastcall KServerSession::SendSyncRequest(KServerSession *this, KThread *thread); | |
void __fastcall KAddressArbiter::Initialize(KAddressArbiter *this, KProcess *owner); | |
Result __fastcall KInterruptEvent::ReenableInterrupt(KInterruptEvent *this); | |
void __fastcall KInterruptTaskManager::EnqueueTask(KInterruptTaskManager *this, KInterruptTask *task); | |
Result __fastcall KThread::InitializeUserThread(KThread *this, u32 ep, u32 arg, u32 stackTop, s32 priority, s32 idealCore, KProcess *parentProcess); | |
Result __fastcall KProcess::GetQtmStaticMappedSize(s32 *out, KProcess *this); | |
Result __fastcall KProcess::GetQtmStaticMappedBase(s32 *out, KProcess *this); | |
Result __fastcall KProcess::GetQtmStaticMappedConversionOffset(s32 *out, KProcess *this); | |
u32 __fastcall KMemoryManager::ConvertSharedMemPaLinearWithAppMemType(u32 pa); | |
void __fastcall ReplyAndReceiveImpl(ReplyAndReceiveArgs *args, KSynchronizationObject **syncObjects); | |
void __fastcall GetThreadListImpl(GetThreadListArgs *args, u32 *tidBuffer); | |
void __fastcall GetProcessListImpl(GetProcessListArgs *args, u32 *pidBuffer); | |
Result __fastcall KDmaChannel::Restart(KDmaChannel *this, u32 dstAddr, u32 srcAddr, u32 size, DmaRestartFlags restartFlags); | |
KPort *__fastcall KPort::KPort(KPort *this); | |
void __fastcall KEvent::Initialize(KEvent *this, KProcess *ownerProcess, ResetType resetType); | |
Result __fastcall KMutex::Initialize(KMutex *this, KProcess *owner, BOOL initiallyLocked); | |
void __fastcall KMutex::ForceUnlock(KMutex *this, KThread *thread); | |
Result __fastcall KProcessPageTable::Initialize(KProcessPageTable *this, u32 pid, bool onlyUseSmallPages); | |
Result __fastcall KProcessPageTable::ControlMemory(KProcessPageTable *this, u32 *outAddr, u32 addr0, u32 addr1, u32 size, u32 op, u32 perms); | |
Result __fastcall KProcessPageTable::MapSharedConfigPages(KProcessPageTable *this, bool canWriteSharedUserPage); | |
Result __fastcall KPageTable::CheckAndUpdateAddrRangeMaskedStateAndPerms(KPageTable *this, u32 addr, u32 numPages, KMemoryState stateMask, KMemoryState expectedState, KMemoryPermission minPerms, KMemoryState newState, KMemoryPermission newPerms); | |
Result __fastcall KInterruptManager::UnbindUserInterruptEventChecked(KInterruptManager *this, KInterruptEvent *interruptEvent, s32 irqId); | |
void __fastcall KMemoryBlockManager::Initialize(KMemoryBlockManager *this, u32 addrSpaceStart, u32 addrSpaceEnd); | |
void __fastcall KInterruptController::EnableWithPriority(s32 irqId, u8 priority); | |
u32 KPerformanceCounterManager::GetOverflowFlags(void); | |
void __fastcall KPerformanceCounterManager::SetVirtualCounterEnabled(KPerformanceCounterManager *this, bool enable); | |
void __fastcall KPerformanceCounterManager::ResetCounters(KPerformanceCounterManager *this, u32 valueMask, u32 overflowMask); | |
void KPerformanceCounterManager::Disable(void); | |
PerformanceCounterEvent __fastcall KPerformanceCounterManager::GetEvent(KPerformanceCounterManager *this, PerformanceCounterName name); | |
u64 __fastcall KPerformanceCounterManager::GetCounterValue(KPerformanceCounterManager *this, PerformanceCounterName name); | |
void __fastcall KPerformanceCounterManager::SetEvent(KPerformanceCounterManager *this, PerformanceCounterName name, PerformanceCounterEvent event); | |
void __fastcall KPerformanceCounterManager::SetCounterValue(KPerformanceCounterManager *this, PerformanceCounterName name, u64 value); | |
void __fastcall KPageTable::InvalidateEntireInstructionCache(); | |
Result __fastcall KProcessPageTable::CopyMemoryForDebug(KProcessPageTable *this, u32 dstAddr, KProcessPageTable *srcPgTbl, u32 srcAddr, u32 size); | |
void __fastcall KDebug::Intialize(KDebug *this, KProcess *process); | |
Result __fastcall KThread::AttachNewToDebug(KThread *this); | |
Result __fastcall KThread::SignalExitToDebug(KThread *this); | |
Result __fastcall KProcess::SetDebugExitedNormallyFlag(KProcess *this); | |
Result __fastcall KThread::SetDebugPauseOnInit(KThread *this); | |
Result __fastcall KProcess::SetDebugTerminatedFlag(KProcess *this); | |
Result __fastcall KDebug::BreakNoRo(KDebug *this, UserBreakType breakReason); | |
Result __fastcall KDebug::GetThreadContext(KDebug *this, ThreadContext *outThreadContext, KThread *thread, ThreadContextControlFlags flags); | |
Result __fastcall KDebug::SetThreadContext(KDebug *this, ThreadContext *threadContext, KThread *thread, ThreadContextControlFlags flags); | |
Result __fastcall KDebug::Attach(KDebug *this, KProcess *process); | |
Result __fastcall KDebug::QueryProcessMemory(KDebug *this, MemoryInfo *outMemInfo, u32 *pgInfo, u32 addr); | |
KThread *__fastcall KThread::FindById(u32 id); | |
void __fastcall KThread::SetSleepPriority(KThread *this, s32 priority); | |
void __fastcall KThread::RestorePriorityAfterSleep(KThread *this); | |
void __fastcall KThread::Exit(KThread *this); | |
Result __fastcall KCodeSet::Initialize(KCodeSet *this, const CodeSetInfo *codeSetInfo, KProcessPageTable *pgTable, u32 textPtr, u32 rodataPtr, u32 dataPtr); | |
bool __fastcall KProcess::IsTerminated(KProcess *this); | |
Result __fastcall KProcess::DumpThreadIds(KProcess *this, s32 *outNumThreads, u32 *threadIdList, s32 threadIdListSize); | |
bool __fastcall KProcess::TerminateImpl1(KProcess *this); | |
KProcess *__fastcall KProcess::OpenById(u32 pid); | |
bool __fastcall KProcess::ReserveResource(KProcess *this, ResourceLimitType type, s32 amount); | |
BOOL __fastcall KProcess::CheckThreadPriority(KProcess *this, s32 priority); | |
void __fastcall KProcess::IncrementThreadCount(KProcess *this); | |
Result *__fastcall MakeResultCode(Result *result, u8 level, u8 summary, u8 module, u16 description); | |
u32 __fastcall KHandleTable::GetTotalAllocatedSize(KHandleTable *this); | |
s64 __fastcall KMemoryBlockManger::GetTotalPrivateMemSize(KMemoryBlockManager *this); | |
s64 __fastcall KMemoryBlockManager::GetTotalCommittedMemory(KMemoryBlockManager *this); | |
s64 __fastcall KMemoryBlockManger::GetTotalPrivateOrSharedMemSize(KMemoryBlockManager *this); | |
u32 __fastcall KThread::GetProcessId(KThread *this); | |
void __fastcall __noreturn KThread::UserThreadStarter(int, int, int, int, int); | |
int KThread::SupervisorThreadStarter(); // weak | |
void __fastcall CallFuncWithStackAllocImpl(void *args, u32 stackAllocSize, FuncWithStackAlloc func); | |
void __fastcall memset(void *, size_t, unsigned __int8); | |
char *__fastcall strncpy(char *dstStr, const char *srcStr, u32 count); | |
void __fastcall KResourceLimit::Initialize(KResourceLimit *this); | |
void __fastcall KPort::Initialize(KPort *this, s32 maxSessionCount); | |
Result __fastcall KDmaManager::InitializeChannel(KDmaManager *this, Handle *outDmaObjectHandle, KDmaChannel **outDmaChannel, s8 channelId, u8 cfgFlags); | |
void *__fastcall _aeabi_vec_ctor_nocookie_nodtor(void *user_array, void *(__fastcall *constructor)(void *), u32 element_size, u32 element_count); | |
s32 __fastcall Ncch::ConvertSize(s32 size, u32 unused, s32 unitSize); | |
void __fastcall __noreturn DispatchExceptionWithRegdump(int, int, int, int, int); | |
Result __fastcall DispatchDebugEventFromException(DebugEventType type, u32 param1, u32 param2); | |
Result __fastcall KDebug::CheckMemoryAddressRange(KDebug *this, u32 addr, u32 size, bool isDstProcess, bool write); | |
void __fastcall KProcess::TerminateCurrentProcess(KProcess *this); | |
u32 __fastcall KPageHeap::GetTotalNumPages(KPageHeap *this); | |
bool __fastcall CallFuncWithStackAlloc(FuncWithStackAlloc func, void *args, u32 stackAllocSize); | |
KThread *__fastcall KHandleTable::ConvertToThreadAllowPseudoHandle(KHandleTable *this, Handle handle); | |
KDebug *__fastcall KHandleTable::ConvertCurProcHandleToDebug(Handle debugHandle); | |
BOOL __fastcall KDebug::IsProcessTerminated(KDebug *this); | |
KResourceLimit *__fastcall KHandleTable::ConvertToResourceLimit(KHandleTable *this, Handle reslimitHandle); | |
KProcess *__fastcall KHandleTable::ConvertToProcessAllowPseudoHandle(KHandleTable *this, Handle handle); | |
void __fastcall KDebug::UnpauseAllThreads(KDebug *this, BOOL checkBreak); | |
u32 __fastcall KProcess::GetLinearAddrRangeBase(KProcess *this); | |
u32 __fastcall KObjectAllocator::CountObjectsOwnedByProcess(KObjectAllocator *this, KProcess *process); | |
void __fastcall KThread::PrepareToRun(KThread *this); | |
Result __fastcall KThread::Initialize(KThread *this, u32 ep, u32 arg, u32 kernelStackTop, u32 stackTop, s32 priority, s32 idealCore, KProcess *parentProcess, KThreadType threadType); | |
void __fastcall _aeabi_memclr4(void *, size_t); // idb | |
void __fastcall _aeabi_memset4(void *data, u8 value, u32 size); | |
BOOL __fastcall CopyBytesFromUser(void *dst, const void *src, u32 size); | |
BOOL __fastcall CopyWordsFromUser(void *dst, const void *src, u32 size); | |
BOOL __fastcall CopyWordFromUser(void *dst, const void *src); | |
int __fastcall CopyStringFromUser(char *dstStr, const char *srcStr, u32 size); | |
BOOL __fastcall CopyBytesToUser(void *dst, const void *src, u32 size); | |
BOOL __fastcall CopyWordsToUser(void *dst, const void *src, u32 dataSize); | |
BOOL __fastcall CopyWordToUser(void *dst, const void *src); | |
int __fastcall CopyStringToUser(char *dstStr, const char *srcStr, u32 size); | |
BOOL __fastcall ClearUserBytes(void *userBuffer, u32 size); | |
BOOL __fastcall ClearUserWords(void *userBuffer, u32 size); | |
BOOL __fastcall ClearUserWord(void *userBuffer); | |
bool __fastcall KDmaAddress::ResetAddress(KDmaAddress *this, u32 newAddr); | |
KAutoObject *__fastcall KAutoObject::KAutoObject(KAutoObject *this); | |
Result __fastcall KProcessPageTable::MapStaticOrIo(KProcessPageTable *this, u32 addr, u32 size, BOOL isIo, KMemoryPermission userPerms); | |
Result __fastcall KDebug::SetThreadVfpContext(KDebug *this, ThreadContext *threadContext, KThread *thread, ThreadContextControlFlags flags); | |
bool __fastcall KResourceLimit::Reserve(KResourceLimit *this, ResourceLimitType category, s32 amount); | |
bool __fastcall KDmaAddress::CheckBufferRangeValid(KDmaAddress *this, s32 minOffset, s32 maxOffset); | |
bool __fastcall KDmaAddress::CheckVirtualAddressBlockUsable(KDmaAddress *this, s32 minOffset, s32 maxOffset, BOOL writePerms); | |
KSynchronizationObject *__fastcall KSynchronizationObject::KSynchronizationObject(KSynchronizationObject *__hidden this); | |
Result __fastcall KObjectAllocator::Register(KObjectAllocator *this, KAutoObject *obj); | |
void __fastcall KPageGroup::IncrefPages(KPageGroup *this); | |
Result __fastcall KPageTable::CheckAndMapPageGroup(KProcessPageTable *this, u32 addr, KPageGroup *pgGroup, KMemoryState state, KMemoryPermission perms); | |
void __fastcall KPageHeap::FreeBlock(KPageHeap *this, u32 addr, u32 numPages); | |
Result __fastcall ControlSystem(SystemOperation op, u32 arg1, u64 arg2); | |
void __fastcall KDmaAddress::Initialize(KDmaAddress *this, u32 dstAddr, bool isDevice, KProcess *process); | |
void __fastcall KDmaBufferSize::ComputeFromConfig(KDmaBufferSize *this, s32 size, DmaDeviceConfig *cfg); | |
bool __fastcall KDmaAddress::CheckPhysicalMemContiguous(KDmaAddress *this, s32 minOffset, s32 maxOffset); | |
Result __fastcall KPageTable::CheckMemoryBlockAttributes(KPageTable *this, u32 addr, u32 size, KMemoryState state, KMemoryPermission perms); | |
Result __fastcall KPageTable::MapL2Entries(KPageTable *this, u32 va, u32 pa, u32 numPages_reused, u32 *attribsPtr, bool isLarge); | |
void __fastcall KSystemControl::StopExtraCoresAndJumpImpl(s32 coreId); | |
Result __fastcall KPageTable::MapL1Entries(KPageTable *this, u32 va, u32 pa, u32 numPages, u32 *attribsPtr, bool isLarge); | |
Result __fastcall KPageTable::MergeContiguousEntries(KPageTable *this, u32 va); | |
Result __fastcall KPageTable::MapContiguousPhysicalAddressRange(KPageTable *this, u32 va, u32 pa, u32 numPages, u32 *mmuAttribs); | |
KPageHeapBlock *__fastcall KPageHeap::AllocateBackwards(KPageHeap *this, u32 size); | |
Result __fastcall KMemoryBlockManager::MutateRange(KMemoryBlockManager *this, u32 va, u32 numPages, KMemoryState state, KMemoryPermission perms, u32 tag); | |
void __fastcall KInterruptController::DisableInterrupt(u32 irqId); | |
void __fastcall KMemoryBlock::ShrinkBlock(KMemoryBlock *this, u32 va, u32 numPages); | |
Result __fastcall KInterruptManager::UnbindKernelInterruptForCore(KInterruptManager *this, s32 irqId, s32 coreId); | |
Result __fastcall KInterruptManager::BindInterrupt(KInterruptManager *this, KInterruptHandler *handler, u32 irqId, s32 coreId, s32 priority, bool autoDisable, bool levelSensitive); | |
Result __fastcall KDebug::DispatchEvent(KDebug *this, DebugEventType type, u32 param1, u32 param2); | |
void __fastcall KScheduler::TrySwitchingThread(KScheduler *this); | |
Result __fastcall KDebug::BuildOrderedListOfThreads(KDebug *this); | |
Result __fastcall KDebug::RequestPause(KDebug *this, KThread *thread); | |
Result __fastcall KDebug::GetThreadVfpContext(KDebug *this, ThreadContext *outThreadContext, KThread *thread, ThreadContextControlFlags flags); | |
Result __fastcall KAutoObject::Initialize(KAutoObject *this); | |
KMemoryBlock *__fastcall KMemoryBlockManager::GetMemoryBlockContainingAddr(KMemoryBlockManager *this, u32 addr); | |
void __fastcall KMemoryBlockManager::DumpInfoMaybe_stubbed(KMemoryBlockManager *this); | |
void __fastcall KScheduler::RemoveThread(KScheduler *this, KThread *thread, s32 prio); | |
void __fastcall KScheduler::TriggerSgi(KScheduler *this); | |
KDmaBlockBase *__fastcall KDmaBlockBase::KDmaBlockBase(KDmaBlockBase *this); | |
void SignalNewThreadEntry(void); | |
Result __fastcall DispatchDebugEvent(DebugEventType type, u32 param1, u32 param2); | |
void __fastcall KAutoObject::IncrementRefcount(KAutoObject *this); | |
KAutoObject *__fastcall KHandleTable::ConvertToAutoObject(KHandleTable *this, Handle handle); | |
Result __fastcall KHandleTable::Add(KHandleTable *this, Handle *outHandle, KAutoObject *obj, u8 typeId); | |
Result __fastcall KPageTable::CheckAddrRangeMaskedStateAndPerms(KPageTable *this, u32 addr, u32 size, KMemoryState stateMask, KMemoryState expectedState, KMemoryPermission minPerms); | |
bool KDmaController::IsManagerFaulting(void); | |
bool __fastcall KDmaController::IsChannelFaulting(s8 channelId); | |
u32 __fastcall KDmaController::GetChannelStatus(s8 channelId); | |
Result __fastcall KPageTable::OperateOnGroup(KPageTable *this, u32 addr, KPageGroup *pgGroup, KMemoryState state, KMemoryPermission perms, KMemoryUpdateFlags updateFlags); | |
u32 __fastcall KMemoryManager::AllocateContiguous(KMemoryManager *this, u32 numPages, u32 pageAlignment, MemoryOperation op); | |
void *__fastcall KPageHeap::AllocateContiguous(KPageHeap *this, u32 size, u32 pageAlignment); | |
void __fastcall KPageManager::IncrefPages(KPageManager *this, u32 addr, u32 numPages); | |
Result __fastcall KPageTable::SplitContiguousEntries(KPageTable *this, u32 va, u32 size); | |
void __fastcall KPageTable::InvalidateAllTlbEntries(KPageTable *this); | |
KMemoryInfo *__fastcall KMemoryBlock::GetInfo(KMemoryInfo *__return_ptr result, KMemoryBlock *this); | |
void __fastcall KVfpRegisterDumpHelper::DumpAndDisableVfpRegsForCore(s32 coreId); | |
void __fastcall KDebug::RequestReschedulingForDebugger(KDebug *this, s32 coreId); | |
Result __fastcall KDebug::EmplaceAysncEventInfo(KDebug *this, DebugEventType type, BOOL needsToBeContinued, u32 param1, u32 param2, u32 param3, u32 param4, u32 param5, u32 param6); | |
Result __fastcall KDebug::BreakCurrentProcess(KDebug *this, KThread *thread); | |
Result __fastcall KDebug::UnbreakCurrentProcess(KDebug *this); | |
Result __fastcall KThread::SetPriority(KThread *this, s32 priority); | |
s32 __fastcall KResourceLimit::GetLimitValue(KResourceLimit *this, ResourceLimitType type); | |
s32 __fastcall KDmaAddress::GetPhysicalChunkSize(KDmaAddress *this, s32 size); | |
void __fastcall KPageGroup::AddRange(KPageGroup *this, u32 addr, u32 numPages); | |
Result __fastcall KPageTable::QueryInfo(KPageTable *this, KMemoryInfo *outMemoryInfo, u32 *pageInfo, u32 addr); | |
void __fastcall KScheduler::AddThread(KScheduler *this, KThread *thread); | |
void __fastcall KScheduler::RescheduleByForce(KScheduler *this, KThread *forcedThread); | |
void __fastcall KScheduler::SwitchThread(KScheduler *this, KThread *forcedThread); | |
Result __fastcall KPageTable::CopyMemoryInterprocessForIpc(KPageTable *this, u32 dstAddr, KPageTable *srcPgTbl, u32 srcAddr, u32 size); | |
void *__fastcall memcpy(void *dst, const void *src, u32 size); | |
void __fastcall KCacheMaintenanceHelper::RequestOtherCoresCacheMaintenanceByMva(bool *outAsync, KCacheMaintenanceOperation op, u32 addr, u32 size); | |
void __fastcall KScheduler::AdjustThreadPriorityChanged(KScheduler *this, KThread *thread, s32 newPrio); | |
void __fastcall KPageHeap::ValidateBlock(KPageHeap *this, KPageHeapBlock *block); | |
void __fastcall KPageHeap::UpdateBlockMac(KPageHeap *this, KPageHeapBlock *block); | |
void __fastcall KPageHeap::SetLastBlock(KPageHeap *this, KPageHeapBlock *block); | |
s64 __fastcall KHardwareTimer::GetSystemTick(KHardwareTimer *this); | |
bool __fastcall KDmaController::IsInterruptActive(s8 channelId); | |
void __fastcall _aeabi_memclr(void *data, u32 size); | |
void __fastcall _aeabi_memset(void *data, u32 size, u32 value); | |
KPageGroup *__fastcall KPageGroup::KPageGroup(KPageGroup *this); | |
Result __fastcall KPageTable::AnalyzeRange(KPageTable *this, KPageGroup *pgGrp, u32 addr, u32 numPages); | |
Result __fastcall KPageTable::CheckAndChangeGroupStateAndPerms(KPageTable *this, u32 addr, KPageGroup *pgGroup, KMemoryState stateMask, KMemoryState expectedState, KMemoryPermission minPerms, KMemoryState newState, KMemoryPermission newPerms); | |
u32 __fastcall KPageGroup::GetTotalNumPages(KPageGroup *this); | |
void __fastcall KPageGroup::EraseAll(KPageGroup *this); | |
KDmaBlockBase *__fastcall KDmaBlockBase::GetChildBlock(KDmaBlockBase *this); | |
void __fastcall KDmaBlockBase::ResetInfo(KDmaBlockBase *this); | |
s32 __fastcall KDmaAddress::CalculateMinimumAlignment(u32 addr); | |
s32 __fastcall KDmaBurstConfig::Calculate(KDmaBurstConfig *this, s32 dataSize, s32 alignment, DmaDeviceConfig *dmaDeviceCfg); | |
void KThreadContext::EnableCurrentThreadVfp(void); | |
void __fastcall KThreadContext::StoreVfpRegsAndDisable(KThreadContext *this); | |
int __fastcall KInterruptController::EndOfInterrupt(s32 irqId, s32 coreId); | |
void __fastcall KInterruptController::ClearInterruptPendingStatus(s32 irqId); | |
void __fastcall KInterruptController::EnableWithPriorityAndTarget(s32 irqId, s32 coreId, u8 priority); | |
void __fastcall KInterruptController::AcknowledgeIrq(KIrqAcknowledgmentInfo *this); | |
void L2C::Disable(void); | |
void __fastcall InitialProcess::InitialProcess(InitialProcess *this, Cxi *cxi); | |
void *__fastcall _aeabi_memcpy4(void *dst, const void *src, u32 size); | |
void __fastcall KWorkerTaskManager::AddTask(KWorkerType type, KWorkerTask *task); | |
void __fastcall KDmaInstructionFactory::ResetCodeBuffer(KDmaInstructionFactory *this); | |
KDmaAddress *__fastcall KDmaAddress::KDmaAddress(KDmaAddress *this); | |
void __fastcall KSynchronizationObject::GetWaitersListBeginIt(KThreadLinkedListNode **firstNode, KSynchronizationObject *this); | |
void __fastcall KSynchronizationObject::GetWaitersListEndIt(KThreadLinkedListLink **endLink, KSynchronizationObject *this); | |
void __fastcall KThread::RelinquishMutex(KThread *this, KMutex *mutex); | |
void __fastcall KThread::AcquireMutex(KThread *this, KMutex *mutex); | |
BOOL __fastcall KHardwareTimer::RegisterTask(KHardwareTimer *this, KTimerTask *task, s64 timepoint); | |
void __fastcall KTranslationTableIterator::CreateFromEntry(u32 **L1TablePtr, KTranslationTableIterator *ttblIterator, KTranslationTableTraversalContext *traversalContext, u32 va); | |
void __fastcall KTranslationTableIterator::Advance(u32 **L1TablePtr, KTranslationTableIterator *ttblIterator, KTranslationTableTraversalContext *traversalContext); | |
void __fastcall KPageManager::FreeContiguous(KPageManager *this, u32 data, u32 numPages, MemoryOperation op); | |
void __fastcall KHardwareTimer::SetHardwareTimer(KHardwareTimer *this); | |
void __fastcall KHardwareTimer::Sanitize(KHardwareTimer *this); | |
void __fastcall KSchedulerLock::UnlockSingleCoreResched(KSchedulerLock *this); | |
void KPageTable::CleanInvalidateEntireDataCacheLocal(void); | |
void __fastcall KPageGroup::~KPageGroup(KPageGroup *this); | |
void __fastcall KLinkedList::~KLinkedList(KLinkedList *this); | |
void __fastcall KInterruptController::SetInterruptPriority(s32 irqId, u8 priority); | |
bool KSystemControl::IsLgr2Capable(void); | |
void __fastcall KCacheMaintenanceHelperTask::DoTask(KCacheMaintenanceHelperTask *this); | |
void __fastcall KThread::SetSchedulingState(KThread *this, KThreadSchedulingState state); | |
void cpu::SynchronizeAllCores(void); | |
void __fastcall KCacheMaintenanceHelper::RequestOtherCoresEntireCacheMaintenance(bool *outAsync, KCacheMaintenanceOperation op); | |
void __fastcall KCacheMaintenanceHelper::Join(bool *async); | |
void __fastcall L2C::InvalidateRange(u32 addrBegin, u32 addrEnd); | |
void L2C::InvalidateAll(void); | |
void __fastcall KThread::SetDebugPauseState(KThread *this, BOOL pause); | |
bool __fastcall KHardwareTimer::CancelTask(KHardwareTimer *this, KTimerTask *task); | |
void __fastcall KThread::RemoveVfpUsageFromCurrentContext(KThread *this); | |
void *__fastcall KSlabHeap::Allocate(KSlabHeap *this); | |
void __fastcall KLinkedList::InsertAfter(KLinkedList *this, KLinkedListLink *it, KLinkedListNode *node); | |
void __fastcall KSlabHeap::Free(KSlabHeap *this, void *obj); | |
void __noreturn kernelpanic(void); | |
void __fastcall KProcess::ReleaseResource(KProcess *this, ResourceLimitType type, s32 amount); | |
void __fastcall KLinkedList::EraseNode(KLinkedList *this, KLinkedListLink **linkPtr); | |
Result __fastcall KPageTable::Operate(KPageTable *this, u32 va, u32 numPages, u32 pa, KMemoryState state, KMemoryPermission perms, KMemoryUpdateFlags updateFlags, u32 region); | |
bool __fastcall KResourceLimit::Release(KResourceLimit *this, ResourceLimitType category, s32 amount); | |
u32 __fastcall KPageTable::ConvertVaToPa(u32 **L1TablePtr, u32 va); | |
void __fastcall KDmaInstructionFactory::EmitMov(KDmaInstructionFactory *this, CoreLinkDma330InstructionFlags flags, u32 addr); | |
u8 __fastcall KDmaController::MakeSwapRegValue(s32 endianSwapSize); | |
KDmaBufferSize *__fastcall KDmaBufferSize::operator+(KDmaBufferSize *__return_ptr __struct_ptr retstr, const KDmaBufferSize *this, s32 rhs); | |
KDmaBufferSize *__fastcall KDmaBufferSize::operator*(KDmaBufferSize *__return_ptr __struct_ptr retstr, const KDmaBufferSize *this, s32 rhs); | |
KDmaBufferSize *__fastcall KDmaBufferSize::operator+(KDmaBufferSize *__return_ptr __struct_ptr retstr, const KDmaBufferSize *this, const KDmaBufferSize *rhs); | |
KDmaBufferSize *__fastcall KDmaBufferSize::operator+=(KDmaBufferSize *this, s32 rhs); | |
void __fastcall KDmaInstructionFactory::EmitWfp(KDmaInstructionFactory *this, u8 flags, s8 deviceId); | |
s32 __fastcall KDmaController::CalculateLoopCountForDepth(s32 numIter, s32 counterId); | |
KDmaBufferSize *__fastcall KDmaBufferSize::operator+=(KDmaBufferSize *this, const KDmaBufferSize *rhs); | |
void __fastcall KDmaBufferSize::operator=(KDmaBufferSize *this, s32 size); | |
KDmaBufferSize *__fastcall KDmaBufferSize::operator*=(KDmaBufferSize *this, s32 rhs); | |
void __fastcall KDmaBufferSize::operator=(KDmaBufferSize *lhs, const KDmaBufferSize *rhs); | |
void __fastcall KDmaDataUnitBlock::EmitMovCcr(KDmaDataUnitBlock *this, KDmaInstructionFactory *instFactory, bool isNotMain); | |
int divby0(); | |
void __fastcall KLightMutex::LockImpl(KLightMutex *this); | |
void __fastcall KLightMutex::UnlockImpl(KLightMutex *this); | |
void __fastcall KSchedulerLock::Lock(KSchedulerLock *this); | |
void __fastcall KScheduler::AdjustThreadScheduling(KScheduler *this, KThread *thread, u8 oldSchedMask); | |
void __fastcall KSchedulerLock::Unlock(KSchedulerLock *this); | |
void __fastcall KSemaphore::DoTask(KInterruptTask *__shifted(KSemaphore,0x14) this); | |
void __fastcall KSynchronizationObject::NotifyWaiters(KSynchronizationObject *this, BOOL pulse); | |
void __fastcall KCleanInvalidateDataCacheOperator::DoRangeOperation(KCleanInvalidateDataCacheOperator *this, u32 addr, u32 size); | |
void __fastcall KPageTable::CleanInvalidateDataCacheRange(u32 addr, u32 size); | |
bool L2C::IsEnabled(void); | |
void __fastcall KProcess::CleanInvalidateDataCacheRange(KProcess *this, u32 dstAddr, u32 dstSize); | |
void __fastcall KPageTable::CleanInvalidateEntireDataCache(); | |
void __fastcall KCleanDataCacheOperator::DoRangeOperation(KCleanDataCacheOperator *this, u32 addr, u32 size); | |
void __fastcall KPageTable::CleanDataCacheRange(u32 addr, u32 size); | |
void __fastcall KObjectAllocator::Deregister(KObjectAllocator *this, KAutoObject *obj); | |
void __fastcall KLightMutex::Unlock(KLightMutex *this); | |
void __fastcall KServerPort::Connect(KServerPort *this, KServerSession *serverSession); | |
Result __fastcall KCodeSegment::Initialize(KCodeSegment *this, CodeSegmentInfo *a2, KProcessPageTable *pageTable, u32 srcAddr); | |
Result __fastcall KHandleTable::Destroy(KHandleTable *this); | |
void __fastcall KMemoryManager::FreeContiguousLocked(KMemoryManager *this, u32 addr, u32 numPages); | |
KPageHeapBlock *__fastcall KMemoryManager::AllocateContiguousBackwards(KMemoryManager *this, u32 numPages, MemoryOperation region); | |
void __fastcall KResourceLimit::SetLimitValue(KResourceLimit *this, ResourceLimitType name, s32 value); | |
Result __fastcall KServerSession::ReceiveSyncRequest(KServerSession *this, KThread *thread); | |
KLightMutex **__fastcall KLightMutex::Lock(KLightMutex **pLightMutex, KLightMutex *this); | |
void KDmaController::KillManagerThread(void); | |
u32 __fastcall KDmaController::GetLoopCounter(s8 channelId, s32 regId); | |
void KDmaController::ClearAllInterrupts(void); | |
u32 __fastcall KDmaController::GetDestinationAddress(s8 channelId); | |
u32 __fastcall KDmaController::GetSourceAddress(s8 channelId); | |
void __fastcall KDmaInstructionFactory::ReplaceFlushPByNop(KDmaInstructionFactory *this); | |
void __fastcall KDmaInstructionFactory::MutateMovDarMovSarInsts(KDmaInstructionFactory *this, u32 dstAddr, u32 srcAddr); | |
void __fastcall KDmaChannel::AbortTransferForPowerStateChange(KDmaChannel *this); | |
void __fastcall KDmaChannel::AbortTransfer(KDmaChannel *this); | |
Result __fastcall KPageTable::CheckAddressRangeSizeAndState(KPageTable *this, u32 addr, u32 size, KMemoryState state); | |
Result __fastcall KPageTable::CheckAddressRangeSizeAndStateFlags(KPageTable *this, u32 addr, u32 size, KMemoryState stateMask, KMemoryState expectedStateFlags); | |
Result __fastcall KPageTable::ChangePageAttributes(KPageTable *this, u32 addr, u32 size, u32 *mmuAttribs); | |
Result __fastcall KPageTable::CheckAndUnmapPageGroup(KPageTable *this, u32 addr, KPageGroup *pgGroup); | |
Result __fastcall KPageTable::MapNewlyAllocatedPhysicalAddressRange(KPageTable *this, u32 va, u32 pa, u32 numPages, u32 *mmuAttrbis); | |
Result __fastcall KPageTable::OperateOnAnyFreeBlockInRegionWithGuardPage(KPageTable *this, u32 *outAddr, u32 blockNumPages, u32 regionStart, u32 regionNumPages, u32 pa, KMemoryState state, KMemoryPermission perms, KMemoryUpdateFlags updateFlags, u32 region); | |
Result __fastcall KPageTable::CreateAlias(KPageTable *this, u32 srcAddr, u32 dstAddr, u32 numPages, KMemoryState expectedStateSrc, KMemoryPermission expectedMinPermsSrc, KMemoryState newStateSrc, KMemoryPermission newPermsSrc, KMemoryState newStateDst, KMemoryPermission newPermsDst); | |
Result __fastcall KPageTable::DestroyAlias(KPageTable *this, u32 srcAddr, u32 dstAddr, u32 numPages, KMemoryState expectedStateSrc, KMemoryPermission expectedMinPermsSrc, KMemoryState expectedStateDst, KMemoryPermission expectedMinPermsDst, KMemoryState newStateSrc, KMemoryPermission newPermsSrc, KMemoryUpdateFlags additionalMemUpdateFlags); | |
void __fastcall KPageTable::Unmap(KPageTable *this, u32 addr, u32 numPages); | |
void __fastcall KPageTable::InitizalizeL1Table(u32 **outL1TablePtr, u32 *L1Table); | |
Result __fastcall KInterruptManager::ReenablePublicInterruptOrFiq(KInterruptManager *this, s32 irqId); | |
void __fastcall KInterruptManager::UnbindUserInterruptEvent(KInterruptManager *this, s32 irqId); | |
void __fastcall KPerformanceCounterManager::BindInterrupts(KPerformanceCounterManager *this); | |
void __fastcall KPageTable::CleanInvalidateInstructionCacheRange(u32 addr, u32 size); | |
Result __fastcall KDebug::PauseSignalingThread(KDebug *this, KThread *thread); | |
Result __fastcall KDebug::AttachNewThread(KDebug *this, KThread *thread); | |
Result __fastcall KDebug::DetachThread(KDebug *this, KThread *thread); | |
Result __fastcall KDebug::IntializeDebugThreads(KDebug *this); | |
Result __fastcall KDebug::PauseProcess(KDebug *this, KThread **outCurrentThreads); | |
Result __fastcall KDebug::EmplaceSyncEventInfo(KDebug *this); | |
Result __fastcall KDebug::GetThreadContextInSvc(KDebug *this, ThreadContext *outThreadContext, KThread *thread, ThreadContextControlFlags flags); | |
Result __fastcall KDebug::ProcessAsyncEventAndEmplaceInfo(KDebug *this, DebugEventType type, u32 param1); | |
Result __fastcall KThread::Sleep(KThread *this, s64 timeout); | |
Result __fastcall KProcess::GetProcessList(s32 *outNumProcesses, u32 *pidBuffer, s32 maxNumProcesses); | |
void __fastcall KSession::Initialize(KSession *this, KClientPort *clientPort); | |
KPageHeapBlock *__fastcall KPageHeap::SplitBlock(KPageHeap *this, KPageHeapBlock *curBlk, u32 newBlockSize); | |
BOOL __fastcall KAffinityMask::CheckCoreAllowed(KAffinityMask *this, u8 coreId); | |
KMemoryBlock *__fastcall KMemoryBlockManager::FindFreeBlockInRegion(KMemoryBlockManager *this, u32 regionStart, u32 regionNumPages, u32 blockNumPages); | |
Result __fastcall KProcessPageTable::UnmapStaticOrIoByPa(KProcessPageTable *this, u32 dstPa, KProcessPageTable *srcPgTbl, u32 srcPa, u32 size); | |
void __fastcall KThreadContext::Load(KThreadContext *ctx); | |
KThreadContext *__fastcall KScheduler::Reschedule(KScheduler *this, _DWORD reused_variable); | |
void __fastcall KCpuTimeLimit::ConfigureTimeLimit(s32 cpuTime); | |
KThread *__fastcall KScheduler::GetNextQueuedThread(KScheduler *this, KThread *thread); | |
s8 __fastcall KDmaManager::TryLockChannel(KDmaManager *this, s8 channelId); | |
Result __fastcall KDmaManager::CheckDeviceConfig(s32 *outMinAlignment, DmaDeviceConfig *deviceCfg, s8 endianSwapSize, bool isDevice); | |
BOOL __fastcall KHandleTable::CloseHandle(KHandleTable *this, Handle handle); | |
void __fastcall KMemoryBlock::GrowBlock(KMemoryBlock *this, u32 va, u32 numPages); | |
Result __fastcall KServerSession::ReplyOrAbortRequest(KServerSession *this, KThread *srcThread, bool reply); | |
Result __fastcall KSynchronization::WaitSynchronizationN(KSynchronization *this, s32 *outIdx, KThread *thread, KSynchronizationObject **objs, s32 numHandles, bool waitAll, s64 timeout); | |
KDmaProgram *__fastcall KDmaProgram::KDmaProgram(KDmaProgram *this); | |
bool __fastcall KSynchronizationObject::AddWaiter(KSynchronizationObject *this, KThread *thread); | |
bool __fastcall KSynchronizationObject::RemoveWaiter(KSynchronizationObject *this, KThread *thread); | |
void __fastcall KDmaController::KillChannelThread(s8 channelId); | |
void __fastcall KDmaInstructionFactory::SetCodeBuffer(KDmaInstructionFactory *this, u8 *codeBuffer, s32 size); | |
void __fastcall KThreadContext::SetVfpGprs(KThreadContext *this, f64 *d); | |
Result KFiqHelper::ReenableInterrupt(void); | |
void __fastcall KServerSession::TranslateOutputIpcParameters(u32 *reqCmdbuf, u32 *srcCmdbuf, KThread *reqThread, KThread *srcThread, u32 reqThreadTls, u32 normalSize, u32 translateSize); | |
Result __fastcall KServerSession::TranslateInputIpcParameters(u32 *dstCmdbuf, u32 *srcCmdbuf, KThread *dstThread, KThread *srcThread, u32 dstTlsVa, u32 normalSize, u32 translateSize); | |
void __fastcall KDmaChannel::Initialize(KDmaChannel *this, KDmaChannelEventHandler *chEvHandler, KDmaObject *dmaObject); | |
void __fastcall KDmaChannel::FinalizeTransfer(KDmaChannel *this); | |
void __fastcall KDmaChannel::StartExecutingCode(KDmaChannel *this, BOOL waitForWfpState); | |
void __fastcall KDmaChannel::BuildProgramAndRun(KDmaChannel *this, BOOL flushPeripheral); | |
void __fastcall KMutex::RecalculatePriority(KMutex *this); | |
Result __fastcall KPageTable::RemapMemoryInterprocess(KPageTable *dstPgTbl, KPageTable *srcPgTbl, u32 dstAddr, u32 srcAddr, u32 numPages, KMemoryState dstMemState, KMemoryPermission dstMemPerms); | |
void __fastcall KPageTable::InvalidateTlbEntryByMva(KPageTable *this, u32 addr); | |
void __fastcall KPageTable::UnmapEntries(KPageTable *this, u32 currentVa, u32 numPages, KPageGroup *outPgGroupUnmapped); | |
Result __fastcall KInterruptManager::ReenablePublicInterrupt(KInterruptManager *this, s32 irqId); | |
void __fastcall KMemoryBlockManager::CoalesceBlocks(KMemoryBlockManager *this); | |
void __fastcall KInterruptController::DisablePeripheralInterrupt(s32 irqId); | |
void __fastcall KInterruptController::ConfigureInterrupt(s32 irqId, bool levelSensitive); | |
void __fastcall KPageTable::CleanInvalidateDataCacheRangeLocal(u32 addr, u32 size); | |
Result __fastcall KDebug::InitializeSyncEventInfo(KDebug *this, KEventInfo *info); | |
Result __fastcall KDebug::InitalizeAsyncEventInfo(KDebug *this, DebugEventType type, KEventInfo *eventInfo, u32 param1, u32 param2, u32 param3, u32 param4, u32 param5, u32 param6); | |
void __fastcall KThread::ForceToTerminate(KThread *this); | |
bool __fastcall KPageGroup::IsEqualRange(KPageGroup *lhs, KPageGroup *rhs); | |
bool __fastcall KDmaAddress::CheckAlignment(KDmaAddress *this, s32 alignment); | |
BOOL __fastcall KMemoryBlock::IncludesRange(KMemoryBlock *this, u32 va, u32 numPages); | |
bool __fastcall KMemoryBlock::Contains(KMemoryBlock *this, u32 addr); | |
void KThreadContext::DisableCurrentThreadVfp(void); | |
void __fastcall KScheduler::UpdateQueue(KScheduler *this); | |
u32 __fastcall KDmaAddress::Advance(KDmaAddress *this, s32 offset); | |
void __fastcall KSynchronization::Cancel(KSynchronization *this, KThread *thread, Result cancelResult); | |
void __fastcall KDmaController::ClearInterrupt(s8 channelId); | |
u32 __fastcall KDmaController::GetChannelProgramCounter(s8 channelId); | |
void __fastcall KDmaController::StartExecutingChannelCode(s8 channelId, u32 codeBufferPa, bool nonSecure); | |
void __fastcall KDmaInstructionFactory::EmitFlushP(KDmaInstructionFactory *this, s8 deviceId); | |
void __fastcall KDmaInstructionFactory::EmitFinalSequence(KDmaInstructionFactory *this, s8 channelId); | |
Result __fastcall KProcessPageTable::MapMemoryForIpc(u32 *outAddr, KPageTable *this, KPageTable *srcPgTbl, u32 srcAddr, u32 size); | |
void __fastcall KProcessPageTable::SwitchContext(KProcessPageTable *this); | |
u32 __fastcall KTranslationTableTraversalContext::InitFromEntry(u32 *outPa, u32 **outL2Entry, u32 entryValue, u32 va); | |
void __fastcall KInterruptController::EnableInterrupt(s32 irqId); | |
void __fastcall KInvalidateDataCacheOperator::DoRangeOperation(KInvalidateDataCacheOperator *this, u32 addr, u32 size); | |
void __fastcall KPageTable::InvalidateDataCacheRange(u32 addr, u32 size); | |
Result __fastcall KDebug::InitializeExceptionDebugEventInfo(KDebug *this, KEventInfo *info); | |
BOOL __fastcall KPageHeap::TryInsert(KPageHeap *this, u32 freedAddr, u32 freedNumPages, KPageHeapBlock *prevBlock, KPageHeapBlock *nextBlock); | |
bool __fastcall AtomicBool::CompareExchangeStrong(AtomicBool *this, bool oldVal, bool newVal); | |
void __fastcall KSynchronizationObject::EraseWaiterNode(KThreadLinkedListLink *outLink, KSynchronizationObject *this, KThreadLinkedListNode **it); | |
int __fastcall ll_udiv_donemoving(unsigned __int64 a1, unsigned int a2, int a3); | |
int __fastcall _aeabi_ldiv0(_DWORD, _DWORD); // weak | |
void _aeabi_idiv0(); | |
void __noreturn KSystemControl::LaunchFirm(void); | |
void __fastcall DestroyDmaChannelInstances(); | |
void HorizonKernelFinalize(void); | |
bool __fastcall KDmaObject::IsSignaled(KDmaObject *this, KThread *thread); | |
bool __fastcall KDmaObject::TryAcquire(KDmaObject *this, KThread *thread); | |
void __fastcall KPageGroup::FreeMemory(KPageGroup *this); | |
void __fastcall KScheduler::Disable(KScheduler *this); | |
KInterruptTask *__fastcall KScheduler::OnInterrupt(KScheduler *this, s32 irqId); | |
void __fastcall KCpuTimeLimiterMode1::OnTimeout(KCpuTimeLimiterMode1 *this); | |
bool __fastcall KSemaphore::IsSignaled(KSemaphore *this, KThread *thread); | |
void __fastcall KSemaphore::Finalize(KSemaphore *this); | |
bool __fastcall KSemaphore::TryAcquire(KSemaphore *this, KThread *thread); | |
bool __fastcall KTimerTask::IsValidTimerTask(KTimerTask *this); | |
void __fastcall KAutoObject::DecrementReferenceCount(KAutoObject *this); | |
bool __fastcall KClientPort::IsSignaled(KClientPort *this, KThread *thread); | |
void __fastcall KClientPort::DecrementSessionCount(KClientPort *this); | |
bool __fastcall KClientPort::TryAcquire(KClientPort *this, KThread *thread); | |
KInterruptTask *__fastcall KDmaManager::OnInterrupt(KDmaManager *this, s32 irqId); | |
void __fastcall KDmaManger::DoTask(KDmaManager *this); | |
void __fastcall KDmaManager::Finalize(KDmaManager *this); | |
void __fastcall KThreadLinkedList::~KThreadLinkedList(KThreadLinkedList *this); | |
bool __fastcall KServerPort::IsSignaled(KServerPort *this, KThread *thread); | |
void __fastcall KServerPort::OnAbort(KServerPort *this); | |
bool __fastcall KServerPort::TryAcquire(KServerPort *this, KThread *thread); | |
void __fastcall KCodeSet::Finalize(KCodeSet *this); | |
Result __fastcall KCodeSegment::Finalize(KCodeSegment *this); | |
void __fastcall KDmaDataUnitBlock::SetInfo(KDmaDataUnitBlock *this, s8 *outLoopDepth, KDmaTransferInfo *dmaTransferInfo); | |
KDmaBlockBase **__fastcall KDmaBlockBase::CalculateSizes(KDmaBlockBase **pThis); | |
void __fastcall KDmaProgram::SetInfo(KDmaProgram *this, s8 *outLoopDepth, KDmaTransferInfo *dmaTransferInfo); | |
void __fastcall KDmaBlockBase::SetInfo(KDmaBlockBase *this, s8 *outLoopDepth, KDmaTransferInfo *dmaTransferInfo); | |
void __fastcall KSharedMemory::Finalize(KSharedMemory *this); | |
bool __fastcall KClientSession::IsSignaled(KClientSession *this, KThread *thread); | |
bool __fastcall KClientSession::TryAcquire(KClientSession *this, KThread *thread); | |
void __fastcall KDmaSmallerTransferBlock::Configure(KDmaSmallerTransferBlock *this, KDmaConfig *dmaCfg, KDmaBlockConfig *dmaBlkCfg, KDmaBlockType type); | |
bool __fastcall KServerSession::IsSignaled(KServerSession *this, KThread *thread); | |
void __fastcall KServerSession::AbortAllRequests(KServerSession *this); | |
void __fastcall KServerSession::NotifyClientClosed(KServerSession *this); | |
bool __fastcall KServerSession::TryAcquire(KServerSession *this, KThread *thread); | |
void __fastcall KSlabHeap::~KSlabHeap(KSlabHeap *this); | |
void __fastcall KAddressArbiter::Finalize(KAddressArbiter *this); | |
KInterruptTask *__fastcall `covariant return thunk to'KInterruptEvent::OnInterrupt(KInterruptEvent *this, s32 irqId); | |
KObjectContainer *__fastcall KObjectContainer::KObjectContainer(KObjectContainer *this); | |
void __fastcall KSynchronization::AbortSynchronization(KSynchronization *this, KSynchronizationObject *obj, Result rescode); | |
void __fastcall KDmaProgram::CalculateLargeSmallBlockSplit(KDmaBlockConfig *largerBlkCfg, KDmaBlockConfig *smallerBlkCfg, s32 dstSize, s32 srcSize, s32 dstStride, s32 srcStride); | |
void __fastcall KDmaProgram::SetTreeStructure(KDmaProgram *this, KDmaTransferInfo *info); | |
void __fastcall KDmaProgram::Configure(KDmaProgram *this, KDmaConfig *dmaCfg, KDmaBlockConfig *dmaBlkCfg, KDmaBlockType type); | |
void __fastcall KDmaLargerTransferBlock::Configure(KDmaLargerTransferBlock *this, KDmaConfig *dmaCfg, KDmaBlockConfig *dmaBlkCfg, KDmaBlockType type); | |
void __fastcall KCpuTimeLimiterMode0::OnTimeout(KCpuTimeLimiterMode0 *this); | |
Result __fastcall KProcess::FreeKernelStackOfThread(KProcess *this, u32 stackAddr); | |
void __fastcall KSynchronizationObject::AbortSynchronization(KSynchronizationObject *this, Result result); | |
void __fastcall KThread::Finalize(KThread *this); | |
void __fastcall KSynchronizationObject::Finalize(KSynchronizationObject *this); | |
s32 __fastcall KDmaController::CalculateLoopDepthFromNumIter(s32 numIterations); | |
bool __fastcall KDmaController::IsEventActive(s8 channelId); | |
u32 KDmaController::GetInterruptStatusRegister(void); | |
void __fastcall KDmaInstructionFactory::SetCurrentInstruction(KDmaInstructionFactory *this, u32 index); | |
void __fastcall KDmaInstructionFactory::EmitAddh(KDmaInstructionFactory *this, u8 flags, s8 deviceId); | |
void __fastcall KDmaInstructionFactory::EmitLdp(KDmaInstructionFactory *this, u8 flags, s8 deviceId); | |
void __fastcall KDmaInstructionFactory::EmitStp(KDmaInstructionFactory *this, u8 flags, s8 deviceId); | |
void __fastcall KDmaInstructionFactory::EmitRmb(KDmaInstructionFactory *this); | |
void __fastcall KDmaInstructionFactory::EmitWmb(KDmaInstructionFactory *this); | |
void __fastcall KDmaInstructionFactory::EmitMovCcr(KDmaInstructionFactory *this, u32 endianSwapSize, u32 dstCacheCtrl, u32 dstProtCtrl, u32 dstBurstLen, u32 dstBurstSize, u32 dstInc, u32 srcCacheCtrl, u32 srcProtCtrl, u32 srcBurstLen, u32 srcBurstSize, u32 srcInc); | |
void __fastcall KDmaInstructionFactory::EmitLd(KDmaInstructionFactory *this, u8 flags); | |
void __fastcall KDmaInstructionFactory::EmitLp(KDmaInstructionFactory *this, s32 numIterations); | |
void __fastcall KDmaInstructionFactory::EmitSt(KDmaInstructionFactory *this, u8 flags); | |
void __fastcall KDmaInstructionFactory::EmitLpEnd(KDmaInstructionFactory *this, u8 flags); | |
KDmaInstructionFactory *__fastcall KDmaInstructionFactory::KDmaInstructionFactory(KDmaInstructionFactory *this); | |
KInterruptTask *__fastcall KVfpRegisterDumpHelperImpl::OnInterrupt(KVfpRegisterDumpHelperImpl *this, s32 irqId); | |
KVfpRegisterDumpHelperImpl *__fastcall KVfpRegisterDumpHelperImpl::KVfpRegisterDumpHelperImpl(KVfpRegisterDumpHelperImpl *this); | |
KInterruptTask *__fastcall KSystemControlHelper::OnInterrupt(KSystemControlHelper *this, s32 irqId); | |
u32 KSystemControl::NotifyProcess9AndFinalize(void); | |
void __noreturn KSystemControl::StopExtraCoresAndJump(void); | |
KInterruptTask *__fastcall KSleepEntrySchedHelperImpl::OnInterrupt(KSleepEntrySchedHelperImpl *this, s32 coreId); | |
void __fastcall KSleepEntrySchedHelperImpl::DoTask(KSleepEntrySchedHelper *this); | |
KSleepEntrySchedHelperImpl *__fastcall KSleepEntrySchedHelperImpl::KSleepEntrySchedHelperImpl(KSleepEntrySchedHelperImpl *this); | |
KInterruptTask *__fastcall KSleepExitSchedHelperImpl::OnInterrupt(KSleepExitSchedHelperImpl *this, s32 coreId); | |
void __fastcall KSleepExitSchedHelperImpl::DoTask(KSleepExitSchedHelper *this); | |
KSleepExitSchedHelperImpl *__fastcall KSleepExitSchedHelperImpl::KSleepExitSchedHelperImpl(KSleepExitSchedHelperImpl *this); | |
KInterruptTask *__fastcall KFiqHelper::OnInterrupt(KFiqHelper *this, s32 irqId); | |
void __fastcall KFiqHelper::DoTask(KFiqHelper *this); | |
KInterruptTask *__fastcall KDmaChannel::OnInterrupt(KDmaChannel *this, s32 irqId); | |
void __fastcall KDmaChannel::DoTask(KDmaChannel *this); | |
void __fastcall `non-virtual thunk to'KDmaChannel::DoWorkerTask(KWorkerTask *__shifted(KDmaChannel,8) this); | |
void __fastcall KDmaChannel::DoWorkerTask(KDmaChannel *this); | |
KDmaChannel *__fastcall KDmaChannel::KDmaChannel(KDmaChannel *this); | |
void __fastcall KDmaChannel::~KDmaChannel(KDmaChannel *this); | |
void __fastcall KClientPort::Destroy(KClientPort *this); | |
void __fastcall KServerPort::Destroy(KServerPort *this); | |
bool __fastcall KEvent::IsSignaled(KEvent *this, KThread *thread); | |
void __fastcall KEvent::OnPulse(KEvent *this); | |
bool __fastcall KMutex::IsSignaled(KMutex *this, KThread *thread); | |
void __fastcall KMutex::OnAbort(KMutex *this); | |
void __fastcall KMutex::Finalize(KMutex *this); | |
void __fastcall KMutex::OnWaiterRemoved(KMutex *this, KThread *thread); | |
void __fastcall KMutex::OnWaiterAdded(KMutex *this, KThread *thread); | |
bool __fastcall KMutex::TryAcquire(KMutex *this, KThread *thread); | |
void __fastcall KTimer::OnAbort(KTimer *this); | |
void __fastcall `non-virtual thunk to'KTimer::OnTimeout(KTimerTask *__shifted(KTimer,0x14) this); | |
void __fastcall KTimer::OnTimeout(KTimer *this); | |
void __fastcall KTimer::Finalize(KTimer *this); | |
bool __fastcall KTimer::TryAcquire(KTimer *this, KThread *thread); | |
Result __fastcall KProcessPageTable::Finalize(KProcessPageTable *this, s32 *outTotalMemoryComitted); | |
KInterruptTask *__fastcall KHardwareTimer::OnInterrupt(KHardwareTimer *this, s32 irqId); | |
void __fastcall KHardwareTimer::SetPrescaler(KHardwareTimer *this, u32 prescaler); | |
void __fastcall KHardwareTimer::DoTask(KHardwareTimer *this); | |
void __fastcall KHardwareTimer::Finalize(KHardwareTimer *this, s32 coreId); | |
void __fastcall KSupervisorPageTable::Finalize(KSupervisorPageTable *this, s32 coreId); | |
void __fastcall KSupervisorPageTable::~KSupervisorPageTable(KSupervisorPageTable *this); | |
Result __fastcall KInterruptManager::ReenableInterruptOnCore(KInterruptManager *this, s32 interruptId, s32 coreId); | |
void __fastcall KInterruptManager::~KInterruptManager(KInterruptManager *this); | |
void __fastcall KMemoryBlockManager::Finalize(KMemoryBlockManager *this); | |
void __fastcall KInterruptController::EnableAndRestoreShared(KInterruptControllerState *this); | |
void __fastcall KInterruptController::DumpAndDisableShared(KInterruptControllerState *state); | |
void __fastcall KInterruptController::EnableAndRestoreLocal(KInterruptControllerState *this); | |
void __fastcall KInterruptController::DumpAndDisableLocal(KInterruptControllerState *state); | |
void __fastcall KInterruptManager::Finalize(KInterruptManager *this, s32 coreId); | |
KInterruptTask *__fastcall KPerformanceCounterManager::OnInterrupt(KPerformanceCounterManager *this, s32 irqId); | |
void __fastcall KPerformanceCounterManager::~KPerformanceCounterManager(KPerformanceCounterManager *this); | |
KInterruptTask *__fastcall KCacheMaintenanceHelperTask::OnInterrupt(KCacheMaintenanceHelperTask *this, s32 irqId); | |
KCacheMaintenanceHelperTask *__fastcall KCacheMaintenanceHelperTask::KCacheMaintenanceHelperTask(KCacheMaintenanceHelperTask *this); | |
void __fastcall KCacheMaintenanceHelper::~KCacheMaintenanceHelper(KCacheMaintenanceHelper *this); | |
KInterruptTask *__fastcall KTerminationHelper::OnInterrupt(KTerminationHelper *this, s32 coreId); | |
KInterruptTask *__fastcall KTlbMaintenanceHelperImpl::OnInterrupt(KTlbMaintenanceHelperImpl *this, s32 irqId); | |
KTlbMaintenanceHelperImpl *__fastcall KTlbMaintenanceHelperImpl::KTlbMaintenanceHelperImpl(KTlbMaintenanceHelperImpl *this); | |
void __fastcall KLevel2TranslationTableAllocator::~KLevel2TranslationTableAllocator(KLevel2TranslationTableAllocator *this); | |
void L2C::Enable(void); | |
void __fastcall KCleanDataCacheOperator::DoEntireOperation(KCleanDataCacheOperator *this); | |
void __fastcall KPageTable::InvalidateDataCacheRangeLocal(u32 addr, u32 size); | |
bool __fastcall KDebug::IsSignaled(KDebug *this, KThread *thread); | |
Result __fastcall KDebug::DestroyDebugThreadList(KDebug *this); | |
Result __fastcall KProcess::SignalExitToDebugNoPause(KProcess *this); | |
void __fastcall KDebug::OnAbort(KDebug *this); | |
bool __fastcall KDebug::TryAcquire(KDebug *this, KThread *thread); | |
bool __fastcall KThread::IsSignaled(KThread *this); | |
void __fastcall `non-virtual thunk to'KThread::DoTask(KInterruptTask *__shifted(KThread,0x2C) this); | |
void __fastcall KThread::DoTask(KThread *this); | |
void __fastcall KThread::AddTryingToAcquireMutex(KThread *this, KMutex *mutex); | |
void __fastcall KThread::RemoveTryingToAcquireMutex(KThread *this, KMutex *mutex); | |
bool __fastcall KThread::TryAcquire(KThread *this); | |
bool __fastcall KProcess::IsSignaled(KProcess *this); | |
void __fastcall KProcess::DecrementThreadCount(KProcess *this); | |
Result __fastcall KProcess::FreeTls(KProcess *this, u32 tlsUserAddr); | |
void __fastcall KProcess::Finalize(KProcess *this); | |
bool __fastcall KProcess::TryAcquire(KProcess *this); | |
void __fastcall KClientSession::Destroy(KClientSession *this); | |
void __fastcall KServerSession::Destroy(KServerSession *this); | |
void __fastcall KSession::Finalize(KSession *this); | |
void __fastcall KDmaObject::GetTypeObj(KTypeObj *outTypeObj, KDmaObject *this); | |
void __fastcall KSemaphore::GetTypeObj(KTypeObj *outTypeObj, KSemaphore *this); | |
KProcess *__fastcall KSemaphore::GetOwnerProcess(KSemaphore *this); | |
void __fastcall KAutoObject::GetTypeObj(KTypeObj *outTypeObj, KSynchronizationObject *this); | |
KProcess *__fastcall KAutoObject::GetOwnerProcess(KAutoObject *this); | |
void __fastcall KClientPort::GetTypeObj(KTypeObj *outTypeObj, KClientPort *this); | |
u32 __fastcall KDmaAddress::GetAdvancedAddrPa(KDmaAddress *this, s32 offset); | |
void __fastcall KServerPort::GetTypeObj(KTypeObj *outTypeObj, KServerPort *this); | |
void __fastcall KDmaDataUnitBlock::EmitInstructions(KDmaDataUnitBlock *this, KDmaSize *outDmaTransferSize, KDmaSize *transferredDmaSize, KDmaInstructionFactory *instFactory, KDmaDirection wfpDirection, KDmaTailInfo *parentDmaTailInfo); | |
s32 __fastcall KDmaBlockBase::ComputeNumberOfBlocks(KDmaBlockBase *this, KDmaSize *dmaSize); | |
BOOL __fastcall KDmaBlockBase::UpdateInfo(KDmaBlockBase *this, KDmaTransferInfo *transferInfo, KDmaBlockBase *block, s32 numBlocks, KDmaTailInfo *tailInfo); | |
void __fastcall KDmaBlockBase::EmitInstructions(KDmaBlockBase *this, KDmaSize *outDmaTransferSize_local, KDmaSize *transferredDmaSize, KDmaInstructionFactory *instFactory, KDmaDirection wfpDirection, KDmaTailInfo *parentDmaTailInfo); | |
void __fastcall KSharedMemory::GetTypeObj(KTypeObj *outTypeObj, KSharedMemory *this); | |
KProcess *__fastcall KSharedMemory::GetOwnerProcess(KSharedMemory *this); | |
void __fastcall KClientSession::GetTypeObj(KTypeObj *outTypeObj, KClientSession *this); | |
bool __fastcall KDmaBufferSize::operator<=(const KDmaBufferSize *this, const KDmaBufferSize *rhs); | |
void __fastcall KResourceLimit::GetTypeObj(KTypeObj *outTypeObj, KResourceLimit *this); | |
void __fastcall KServerSession::GetTypeObj(KTypeObj *outTypeObj, KServerSession *this); | |
void __fastcall KAddressArbiter::GetTypeObj(KTypeObj *outTypeObj, KAddressArbiter *this); | |
KProcess *__fastcall KAddressArbiter::GetOwnerProcess(KAddressArbiter *this); | |
void __fastcall KDmaProgram::EmitInstructions(KDmaProgram *this, KDmaSize *outDmaTransferSize, KDmaSize *transferredDmaSize, KDmaInstructionFactory *instFactory, KDmaDirection wfpDirection, KDmaTailInfo *parentDmaTailInfo); | |
void __fastcall KSynchronizationObject::GetTypeObj(KTypeObj *outTypeObj, KSynchronizationObject *this); | |
void __fastcall KPort::GetTypeObj(KTypeObj *outTypeObj, KPort *this); | |
void __fastcall KEvent::GetTypeObj(KTypeObj *outTypeObj, KEvent *this); | |
KProcess *__fastcall KEvent::GetOwnerProcess(KEvent *this); | |
void __fastcall KMutex::GetTypeObj(KTypeObj *outTypeObj, KMutex *this); | |
KProcess *__fastcall KMutex::GetOwnerProcess(KMutex *this); | |
void __fastcall KTimer::GetTypeObj(KTypeObj *outTypeObj, KTimer *this); | |
KProcess *__fastcall KTimer::GetOwnerProcess(KTimer *this); | |
void __fastcall KDebug::GetTypeObj(KTypeObj *outTypeObj, KDebug *this); | |
void __fastcall KThread::GetTypeObj(KTypeObj *outTypeObj, KThread *this); | |
void __fastcall KCodeSet::GetTypeObj(KTypeObj *outTypeObj, KCodeSet *this); | |
s32 __fastcall KDmaSize::operator/(KDmaSize *this, const KDmaSize *rhs); | |
void __fastcall KProcess::GetTypeObj(KTypeObj *outTypeObj, KProcess *this); | |
void __fastcall KSession::GetTypeObj(KTypeObj *outTypeObj, KSession *this); | |
void __fastcall KEvent::DoTask(KInterruptTask *__shifted(KEvent,0x14) this); | |
bool __fastcall KTimer::IsValidTimerTask(KTimerTask *__shifted(KTimer,0x14) this); | |
void __fastcall KThread::OnTimeout(KTimerTask *__shifted(KThread,0x14) this); | |
void __fastcall KThread::DoWorkerTask(KWorkerTask *__shifted(KThread,0x24) this); | |
KInterruptTask *__fastcall KThread::OnInterrupt(KInterruptTask *this, s32 irqId); | |
void __fastcall KDmaManager::OnChannelUnlocked(KDmaManager *__shifted(KDmaManager,8) this, s8 channelId); | |
u32 __fastcall KInvalidateDataCacheOperator::GetThreshold(KInvalidateDataCacheOperator *this); | |
u32 __fastcall KCleanInvalidateDataCacheOperator::GetThreshold(KCleanInvalidateDataCacheOperator *this); | |
u32 __fastcall KCleanDataCacheOperator::GetThreshold(KCleanDataCacheOperator *this); | |
AtomicBool *__fastcall AtomicBool::AtomicBool(AtomicBool *this); | |
void __fastcall KDmaObject::Destroy(KDmaObject *this); | |
void __fastcall KSemaphore::Destroy(KSemaphore *this); | |
void __fastcall KSharedMemory::Destroy(KSharedMemory *this); | |
void __fastcall KResourceLimit::Destroy(KResourceLimit *this); | |
void __fastcall KAddressArbiter::Destroy(KAddressArbiter *this); | |
void __fastcall KPort::Destroy(KPort *this); | |
void __fastcall KEvent::Destroy(KEvent *this); | |
void __fastcall KMutex::Destroy(KMutex *this); | |
void __fastcall KTimer::Destroy(KTimer *this); | |
void __fastcall KDebug::Destroy(KDebug *this); | |
void __fastcall KThread::Destroy(KThread *this); | |
void __fastcall KCodeSet::Destroy(KCodeSet *this); | |
void __fastcall KProcess::Destroy(KProcess *this); | |
void __fastcall KSession::Destroy(KSession *this); | |
void __noreturn WaitForeverAndAckSgis(void); | |
void __noreturn HandleResetException(); | |
BOOL __fastcall DispatchExceptionToUser(ExceptionDispatchContext *ctx, ERRF_ExceptionInfo *excInfo); | |
void __fastcall DispatchDataAbortException(ExceptionDispatchContext *ctx); | |
void __fastcall DispatchPrefetchAbortException(ExceptionDispatchContext *ctx); | |
void __fastcall DispatchVfpException(ExceptionDispatchContext *ctx); | |
void __fastcall cpu::WaitCycles(u32 numCycles); | |
void __fastcall ExecuteOnExceptionStackInAxiWram(u32 arg, void (__fastcall *func)(s32 arg)); | |
void EnableVfpAfterException(void); | |
void __fastcall __noreturn KSystemControl::HardwareResetImpl(s32 srcCoreId); | |
void __fastcall KSystemControl::HardwareReset(s32 srcCoreId); | |
void KSystemControl::PowerVramDown(void); | |
void KSystemControl::MakeFcramFinalRead(void); | |
void KSystemControl::SetFcramInSelfRefreshMode(void); | |
void KSystemControl::SetFcramInNormalMode(void); | |
void __fastcall KSystemControl::SleepSystemImpl(s32 srcCoreId); | |
void __fastcall KSystemControl::SleepSystem(s32 srcCoreId); | |
BOOL __fastcall KInterruptController::IsInterruptPending(s32 irqId); | |
//------------------------------------------------------------------------- | |
// Data declarations | |
volatile Config11Registers PA_CONFIG11; | |
volatile PdnRegisters PA_PDN; | |
volatile PxiRegisters PA_PXI; | |
volatile Mp11PrivateMemRegion PA_MPCORE; | |
u32 *crt0::L1TableAddresses[4] = { (u32 *)0x1FFF8000, (u32 *)0x1FFFC000, (u32 *)0x1F3F8000, (u32 *)0x1F3FC000 }; | |
u32 *crt0::L2TableAddresses_FFF[4] = { (u32 *)0x1FFF7000, (u32 *)0x1FFF7400, (u32 *)0x1FFF7800, (u32 *)0x1FFF7C00 }; | |
u32 crt0::idleThreadStacks[4] = { 536813568u, 524230656u, 524234752u, 524238848u }; | |
u32 crt0::coreCtxAddrs[4] = { 536817664u, 524242944u, 524247040u, 524251136u }; | |
_UNKNOWN unk_1FFB0414; // weak | |
int (*SHT__INIT_ARRAY__Base)() = (int (*)())0x320; // weak | |
void *off_1FFF4A64 = (void *)0x17E00100; // weak | |
void *off_1FFF4A68 = (void *)0x17E01000; // weak | |
void *off_1FFF4A6C = (void *)0x17E01280; // weak | |
void *off_1FFF4A70 = (void *)0x1FFFFFDC; // weak | |
char *off_1FFF4A74 = &crt0::core1ReadyForFirmlaunch; // weak | |
volatile bool crt0::core1ReadyForFirmlaunch = false; | |
volatile Arm11SysRv SYSRV; | |
int _dso_handle = 1198540656; // idb | |
void *svcTable[126] = | |
{ | |
NULL, | |
&SvcControlMemory, | |
&SvcQueryMemory, | |
&SvcExitProcess, | |
&SvcGetProcessAffinityMask, | |
&SvcSetProcessAffinityMask, | |
&SvcGetProcessIdealProcessor, | |
&SvcSetProcessIdealProcessor, | |
&SvcCreateThread, | |
&SvcExitThread, | |
&SvcSleepThread, | |
&SvcGetThreadPriority, | |
&SvcSetThreadPriority, | |
&SvcGetThreadAffinityMask, | |
&SvcSetThreadAffinityMask, | |
&SvcGetThreadIdealProcessor, | |
&SvcSetThreadIdealProcessor, | |
&SvcGetCurrentProcessorNumber, | |
&SvcRun, | |
&SvcCreateMutex, | |
&SvcReleaseMutex, | |
&SvcCreateSemaphore, | |
&SvcReleaseSemaphore, | |
&SvcCreateEvent, | |
&SvcSignalEvent, | |
&SvcClearEvent, | |
&SvcCreateTimer, | |
&SvcSetTimer, | |
&SvcCancelTimer, | |
&SvcClearTimer, | |
&SvcCreateMemoryBlock, | |
&SvcMapMemoryBlock, | |
&SvcUnmapMemoryBlock, | |
&SvcCreateAddressArbiter, | |
&SvcArbitrateAddress, | |
&SvcCloseHandle, | |
&SvcWaitSynchronization1, | |
&SvcWaitSynchronizationN, | |
&SvcSignalAndWait, | |
&SvcDuplicateHandle, | |
&SvcGetSystemTick, | |
&SvcGetHandleInfo, | |
&SvcGetSystemInfo, | |
&SvcGetProcessInfo, | |
&SvcGetThreadInfo, | |
&SvcConnectToPort, | |
&SvcSendSyncRequest1, | |
&SvcSendSyncRequest2, | |
&SvcSendSyncRequest3, | |
&SvcSendSyncRequest4, | |
&SvcSendSyncRequest, | |
&SvcOpenProcess, | |
&SvcOpenThread, | |
&SvcGetProcessId, | |
&SvcGetProcessIdOfThread, | |
&SvcGetThreadId, | |
&SvcGetResourceLimit, | |
&SvcGetResourceLimitLimitValues, | |
&SvcGetResourceLimitCurrentValues, | |
&SvcGetThreadContext, | |
&SvcBreak, | |
&SvcOutputDebugString, | |
&SvcControlPerformanceCounter, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
&SvcCreatePort, | |
&SvcCreateSessionToPort, | |
&SvcCreateSession, | |
&SvcAcceptSession, | |
&SvcReplyAndReceive1, | |
&SvcReplyAndReceive2, | |
&SvcReplyAndReceive3, | |
&SvcReplyAndReceive4, | |
&SvcReplyAndReceive, | |
&SvcBindInterrupt, | |
&SvcUnbindInterrupt, | |
&SvcInvalidateProcessDataCache, | |
&SvcStoreProcessDataCache, | |
&SvcFlushProcessDataCache, | |
&SvcStartInterProcessDma, | |
&SvcStopDma, | |
&SvcGetDmaState, | |
&SvcRestartDma, | |
&SvcSetGpuProt, | |
&SvcSetWifiEnabled, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
&SvcDebugActiveProcess, | |
&SvcBreakDebugProcess, | |
&SvcTerminateDebugProcess, | |
&SvcGetProcessDebugEvent, | |
&SvcContinueDebugEvent, | |
&SvcGetProcessList, | |
&SvcGetThreadList, | |
&SvcGetDebugThreadContext, | |
&SvcSetDebugThreadContext, | |
&SvcQueryDebugProcessMemory, | |
&SvcReadDebugProcessMemory, | |
&SvcWriteDebugProcessMemory, | |
&SvcSetHardwareBreakPoint, | |
&SvcGetDebugThreadParam, | |
NULL, | |
NULL, | |
&SvcControlProcessMemory, | |
&SvcMapProcessMemory, | |
&SvcUnmapProcessMemory, | |
&SvcCreateCodeSet, | |
&Svc0x74_CodeSetRelated_stubbed, | |
&SvcCreateProcess, | |
&SvcTerminateProcess, | |
&SvcSetProcessResourceLimits, | |
&SvcCreateResourceLimit, | |
&SvcSetResourceLimitLimitValues, | |
&SvcFlushCodeSegment, | |
NULL, | |
&SvcControlSystem, | |
&SvcQueryProcessMemory | |
}; // weak | |
_UNKNOWN loc_FFF1FFFC; // weak | |
_UNKNOWN loc_FFF20000; // weak | |
_DWORD dword_FFF26E70[16] = | |
{ | |
-252645136, | |
-477218589, | |
-678152731, | |
-858993460, | |
-1022611261, | |
-1171354718, | |
-1307163960, | |
-1431655766, | |
-1546188227, | |
-1651910499, | |
-1749801491, | |
-1840700270, | |
-1925330168, | |
-2004318072, | |
-2078209982, | |
2147483648 | |
}; // weak | |
int dword_FFF2E000 = 22534; // weak | |
KInterruptTask_vtbl KSleepEntrySchedHelperImpl::vt = | |
{ | |
&KSleepEntrySchedHelperImpl::OnInterrupt, | |
&KSleepEntrySchedHelperImpl::DoTask | |
}; | |
KInterruptTask_vtbl KSleepExitSchedHelperImpl::vt = { &KSleepExitSchedHelperImpl::OnInterrupt, &KSleepExitSchedHelperImpl::DoTask }; | |
KInterruptTask_vtbl KCacheMaintenanceHelperTask::vt = | |
{ | |
&KCacheMaintenanceHelperTask::OnInterrupt, | |
&KCacheMaintenanceHelperTask::DoTask | |
}; | |
KInterruptHandler_vtbl KCacheMaintenanceHelper::vt = { &KCacheMaintenanceHelper::OnInterrupt }; | |
u32 g_permsToMmuAttribLut[16] = { 0u, 0u, 0u, 0u, 528u, 560u, 0u, 0u, 0u, 0u, 0u, 0u, 16u, 32u, 0u, 48u }; | |
KInterruptHandler_vtbl KTlbMaintenanceHelperImpl::vt = { &KTlbMaintenanceHelperImpl::OnInterrupt }; | |
KInterruptHandler_vtbl KPerformanceCounterControlHelper::vt = { &KPerformanceCounterControlHelper::OnInterrupt }; | |
int off_FFF2E15C = -857691; // weak | |
KCacheOperator_vtbl KCleanDataCacheOperator::vt = | |
{ | |
&KCleanDataCacheOperator::DoRangeOperation, | |
&KCleanDataCacheOperator::DoEntireOperation, | |
&KCleanDataCacheOperator::GetThreshold | |
}; | |
KCacheOperator_vtbl KInvalidateDataCacheOperator::vt = | |
{ | |
&KInvalidateDataCacheOperator::DoRangeOperation, | |
&KInvalidateDataCacheOperator::DoEntireOperation_actuallyCleanInv, | |
&KInvalidateDataCacheOperator::GetThreshold | |
}; | |
KInterruptTask_vtbl KFiqHelper::vt = { &KFiqHelper::OnInterrupt, &KFiqHelper::DoTask }; | |
KSynchronizationObject_vtbl KDmaObject::vt = | |
{ | |
NULL, | |
NULL, | |
&KDmaObject::Destroy, | |
&KSynchronizationObject::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KDmaObject::GetTypeObj, | |
0u, | |
&KSynchronizationObject::OnWaiterAdded, | |
&KSynchronizationObject::OnWaiterRemoved, | |
&KDmaObject::OnAbort, | |
&KDmaObject::IsSignaled, | |
&KDmaObject::TryAcquire, | |
&KSynchronizationObject::OnPulse | |
}; | |
KInterruptTask_vtbl KScheduler::vt = { &KScheduler::OnInterrupt, &KScheduler::DoTask }; | |
KAutoObject_vtbl KAutoObject::vt = | |
{ | |
NULL, | |
NULL, | |
&KAutoObject::Destroy, | |
&KAutoObject::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KAutoObject::GetTypeObj | |
}; | |
KSynchronizationObject_vtbl KClientPort::vt = | |
{ | |
NULL, | |
NULL, | |
&KClientPort::Destroy, | |
&KSynchronizationObject::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KClientPort::GetTypeObj, | |
0u, | |
&KSynchronizationObject::OnWaiterAdded, | |
&KSynchronizationObject::OnWaiterRemoved, | |
&KSynchronizationObject::OnAbort, | |
&KClientPort::IsSignaled, | |
&KClientPort::TryAcquire, | |
&KSynchronizationObject::OnPulse | |
}; | |
KInterruptTask_vtbl KDmaManager::vt = { &KDmaManager::OnInterrupt, &KDmaManger::DoTask }; | |
KDmaChannelEventHandler_vt KDmaManager::vt_KDmaChannelEventHandler = { &KDmaManager::OnChannelTransferFinished, &KDmaManager::OnChannelUnlocked }; | |
KSynchronizationObject_vtbl KServerPort::vt = | |
{ | |
NULL, | |
NULL, | |
&KServerPort::Destroy, | |
&KSynchronizationObject::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KServerPort::GetTypeObj, | |
0u, | |
&KSynchronizationObject::OnWaiterAdded, | |
&KSynchronizationObject::OnWaiterRemoved, | |
&KServerPort::OnAbort, | |
&KServerPort::IsSignaled, | |
&KServerPort::TryAcquire, | |
&KSynchronizationObject::OnPulse | |
}; | |
KDmaBlockBase_vtbl KDmaBlockBase::vt = { NULL, NULL, NULL, &KDmaBlockBase::SetInfo, &KDmaBlockBase::EmitInstructions }; | |
KAutoObject_vtbl KSharedMemory::vt = | |
{ | |
NULL, | |
NULL, | |
&KSharedMemory::Destroy, | |
&KSharedMemory::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KSharedMemory::GetOwnerProcess, | |
&KSharedMemory::GetTypeObj | |
}; | |
KSynchronizationObject_vtbl KClientSession::vt = | |
{ | |
NULL, | |
NULL, | |
&KClientSession::Destroy, | |
&KSynchronizationObject::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KClientSession::GetTypeObj, | |
0u, | |
&KSynchronizationObject::OnWaiterAdded, | |
&KSynchronizationObject::OnWaiterRemoved, | |
&KSynchronizationObject::OnAbort, | |
&KClientSession::IsSignaled, | |
&KClientSession::TryAcquire, | |
&KSynchronizationObject::OnPulse | |
}; | |
KAutoObject_vtbl KResourceLimit::vt = | |
{ | |
NULL, | |
NULL, | |
&KResourceLimit::Destroy, | |
&KResourceLimit::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KResourceLimit::GetTypeObj | |
}; | |
KSynchronizationObject_vtbl KServerSession::vt = | |
{ | |
NULL, | |
NULL, | |
&KServerSession::Destroy, | |
&KSynchronizationObject::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KServerSession::GetTypeObj, | |
0u, | |
&KSynchronizationObject::OnWaiterAdded, | |
&KSynchronizationObject::OnWaiterRemoved, | |
&KSynchronizationObject::OnAbort, | |
&KServerSession::IsSignaled, | |
&KServerSession::TryAcquire, | |
&KSynchronizationObject::OnPulse | |
}; | |
KAutoObject_vtbl KAddressArbiter::vt = | |
{ | |
NULL, | |
NULL, | |
&KAddressArbiter::Destroy, | |
&KAddressArbiter::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAddressArbiter::GetOwnerProcess, | |
&KAddressArbiter::GetTypeObj | |
}; | |
KSynchronizationObject_vtbl KSynchronizationObject::vt = | |
{ | |
NULL, | |
NULL, | |
&KAutoObject::Destroy, | |
&KSynchronizationObject::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KSynchronizationObject::GetTypeObj, | |
0u, | |
&KSynchronizationObject::OnWaiterAdded, | |
&KSynchronizationObject::OnWaiterRemoved, | |
&KSynchronizationObject::OnAbort, | |
&KSynchronizationObject::IsSignaled, | |
&KSynchronizationObject::IsSignaled, | |
&KSynchronizationObject::OnPulse | |
}; | |
KInterruptHandler_vtbl KVfpRegisterDumpHelperImpl::vt = { &KVfpRegisterDumpHelperImpl::OnInterrupt }; | |
KInterruptTask_vtbl KDmaChannel::vt = { &KDmaChannel::OnInterrupt, &KDmaChannel::DoTask }; | |
KWorkerTask_vtbl KDmaChannel::vt_WorkerTask = { &`non-virtual thunk to'KDmaChannel::DoWorkerTask }; | |
KAutoObject_vtbl KPort::vt = | |
{ | |
NULL, | |
NULL, | |
&KPort::Destroy, | |
&KAutoObject::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KPort::GetTypeObj | |
}; | |
KInterruptEvent_vtbl KEvent::vt = | |
{ | |
NULL, | |
NULL, | |
&KEvent::Destroy, | |
&KEvent::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KEvent::GetOwnerProcess, | |
&KEvent::GetTypeObj, | |
0u, | |
&KSynchronizationObject::OnWaiterAdded, | |
&KSynchronizationObject::OnWaiterRemoved, | |
&KSynchronizationObject::OnAbort, | |
&KEvent::IsSignaled, | |
&KEvent::TryAcquire, | |
&KEvent::OnPulse, | |
&`covariant return thunk to'KInterruptEvent::OnInterrupt | |
}; | |
KInterruptTask_vtbl KEvent::vt_KInterruptTask = { &KInterruptEvent::OnInterrupt, &KEvent::DoTask }; | |
KSynchronizationObject_vtbl KMutex::vt = | |
{ | |
NULL, | |
NULL, | |
&KMutex::Destroy, | |
&KMutex::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KMutex::GetOwnerProcess, | |
&KMutex::GetTypeObj, | |
0u, | |
&KMutex::OnWaiterAdded, | |
&KMutex::OnWaiterRemoved, | |
&KMutex::OnAbort, | |
&KMutex::IsSignaled, | |
&KMutex::TryAcquire, | |
&KSynchronizationObject::OnPulse | |
}; | |
KTimerTask_vtbl KDummyTimerTask::vt = { &KDummyTimerTask::OnTimeout, &KTimerTask::IsValidTimerTask }; | |
KInterruptTask_vtbl KHardwareTimer::vt = { &KHardwareTimer::OnInterrupt, &KHardwareTimer::DoTask }; | |
KInterruptHandler_vtbl KPerformanceCounterManager::vt = { &KPerformanceCounterManager::OnInterrupt }; | |
KSynchronizationObject_vtbl KDebug::vt = | |
{ | |
NULL, | |
NULL, | |
&KDebug::Destroy, | |
&KSynchronizationObject::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KDebug::GetTypeObj, | |
0u, | |
&KSynchronizationObject::OnWaiterAdded, | |
&KSynchronizationObject::OnWaiterRemoved, | |
&KDebug::OnAbort, | |
&KDebug::IsSignaled, | |
&KDebug::TryAcquire, | |
&KSynchronizationObject::OnPulse | |
}; | |
KWorkerTask_vtbl KDebug::vt_KWorkerTask = { &KDebug::DoWorkerTask }; | |
KSynchronizationObject_vtbl KThread::vt = | |
{ | |
NULL, | |
NULL, | |
&KThread::Destroy, | |
&KThread::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KThread::GetTypeObj, | |
0u, | |
&KSynchronizationObject::OnWaiterAdded, | |
&KSynchronizationObject::OnWaiterRemoved, | |
&KSynchronizationObject::OnAbort, | |
&KThread::IsSignaled, | |
&KThread::TryAcquire, | |
&KSynchronizationObject::OnPulse | |
}; | |
KTimerTask_vtbl KThread::vt_KTimerTask = { &KThread::OnTimeout, &KTimerTask::IsValidTimerTask }; | |
KWorkerTask_vtbl KThread::vt_KWorkerTask = { &KThread::DoWorkerTask }; | |
KInterruptTask_vtbl KThread::vt_KInterruptTask = { &KThread::OnInterrupt, &`non-virtual thunk to'KThread::DoTask }; | |
KAutoObject_vtbl KCodeSet::vt = | |
{ | |
NULL, | |
NULL, | |
&KCodeSet::Destroy, | |
&KCodeSet::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KCodeSet::GetTypeObj | |
}; | |
KAutoObject_vtbl KSession::vt = | |
{ | |
NULL, | |
NULL, | |
&KSession::Destroy, | |
&KSession::Finalize, | |
&KAutoObject::DecrementReferenceCount, | |
&KAutoObject::GetOwnerProcess, | |
&KSession::GetTypeObj | |
}; | |
_UNKNOWN unk_FFF2EFFF; // weak | |
KLightMutex g_dmaManagerLock = { NULL, 0, 0 }; | |
KSystemControl g_systemControl = | |
{ | |
{ false, false, false }, | |
true, | |
false, | |
6u, | |
0u, | |
0u, | |
0u, | |
{ &PXI, (vu32 *)0xFFFC0004, (vu32 *)0xFFFC0008, (vu32 *)0xFFFC000C }, | |
&PDN_MPCORE_CLKCNT, | |
&HID, | |
SYSTEMOP_CONFIGURE_N3DS_CPU_L2C, | |
1, | |
0u, | |
3993444352u, | |
0u, | |
0uLL, | |
{ NULL, 0, 0 }, | |
0uLL | |
}; | |
bool g_scheduledOut[8] = { false, false, true, false, true, true, true, true }; // weak | |
u32 g_coreSynchronizationCount = 0u; | |
KLightMutex g_l2cLock = { NULL, 0, 0 }; | |
u32 g_timerPrescaler = 0u; | |
u32 g_wdPrescaler = 0u; | |
KLightMutex g_eventSignalMutex = { NULL, 0, 0 }; | |
KLightMutex g_objectNameListMutex = { NULL, 0, 0 }; | |
u32 g_memoryManagementNonce = 2201152216u; | |
u32 g_pidCounter = 40u; | |
bool g_sysmoduleReslimitSet = false; | |
KCpuTimeLimitCategory g_schedulerCurrentlyAllowedCategoryForMode0 = KCPUTIMELIMIT_CATEGORY_SYSMODULE; | |
u32 g_schedulerAppPreemptionMode = 0u; | |
KCpuTimeLimit *g_cpuTimeLimitListHead = &unk_FFF93D6C; | |
KSchedulerLock g_schedulerLock = { NULL, 0 }; | |
KThreadIntrusiveList g_schedulerPreemptedThreadList = { { NULL, NULL } }; | |
u32 g_threadIdCounter = 223u; | |
KLightMutex g_timerOpsMutex = { NULL, 0, 0 }; | |
KernelState g_kernelState = KSTATE_RUNNING; | |
KSynchronization g_synchronization = { 0u }; | |
KernelSharedConfig *g_kernelSharedConfigPagePtr = &g_kernelSharedConfig; // weak | |
u32 g_userSharedConfigPagePtr = 3993309184u; | |
_UNKNOWN unk_FFF2F0E0; // weak | |
_UNKNOWN unk_FFF2F0E8; // weak | |
u32 g_perfCounterMgrExclusivePid = 4294967295u; | |
KFiqState g_fiqState = KFIQSTATE_UNBOUND; | |
int `guard variable for'KObjectContainer<KDmaObject>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KDmaObject>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KSemaphore>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KSemaphore>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KSharedMemory>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KSharedMemory>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KResourceLimit>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KResourceLimit>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KAddressArbiter>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KAddressArbiter>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KPort>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KPort>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KEvent>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KEvent>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KMutex>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KMutex>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KTimer>::KObjectContainer(void)::initialized = 0; // idb | |
int `guard variable for'KSlabHeap<KTimer>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KDebug>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KDebug>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KThread>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KThread>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KCodeSet>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KCodeSet>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KProcess>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KProcess>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KObjectContainer<KSession>::KObjectContainer(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KSession>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KBlockInfo>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KEventInfo>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KObjectName>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KMemoryBlock>::KSlabHeap(void)::initialized = 0; // weak | |
int `guard variable for'KSlabHeap<KThreadLocalPage>::KSlabHeap(void)::initialized = 0; // idb | |
int `guard variable for'KSlabHeap<KDebugThread>::KSlabHeap(void)::initialized = 0; // weak | |
KVfpRegisterDumpHelper g_vfpRegisterDumpHelper = | |
{ | |
{ | |
{ { &KVfpRegisterDumpHelperImpl::vt }, NULL }, | |
{ { &KVfpRegisterDumpHelperImpl::vt }, NULL }, | |
{ { &KVfpRegisterDumpHelperImpl::vt }, NULL }, | |
{ { &KVfpRegisterDumpHelperImpl::vt }, NULL } | |
} | |
}; | |
KSleepEntrySchedHelper g_sleepEntrySchedHelper = | |
{ | |
{ | |
{ { { &KSleepEntrySchedHelperImpl::vt }, NULL } }, | |
{ { { &KSleepEntrySchedHelperImpl::vt }, NULL } }, | |
{ { { &KSleepEntrySchedHelperImpl::vt }, NULL } }, | |
{ { { &KSleepEntrySchedHelperImpl::vt }, NULL } } | |
} | |
}; | |
KSleepExitSchedHelper g_sleepExitSchedHelper = | |
{ | |
{ | |
{ { { &KSleepExitSchedHelperImpl::vt }, NULL } }, | |
{ { { &KSleepExitSchedHelperImpl::vt }, NULL } }, | |
{ { { &KSleepExitSchedHelperImpl::vt }, NULL } }, | |
{ { { &KSleepExitSchedHelperImpl::vt }, NULL } } | |
} | |
}; | |
KThreadLinkedList g_debuggerThreadLinkedList = | |
{ | |
0u, | |
{ (KThreadLinkedListNode *)0xFFF2F1E4, (KThreadLinkedListNode *)0xFFF2F1E4 } | |
}; | |
KCacheMaintenanceHelper g_cacheMaintenanceHelper = | |
{ | |
{ &KCacheMaintenanceHelper::vt }, | |
KCACHEMAINTOP_CLEANINV_ENTIRE_DCACHE, | |
true, | |
2u, | |
&unk_FFF80A90, | |
0u, | |
0u, | |
{ { NULL, NULL } }, | |
{ | |
{ { { &KCacheMaintenanceHelperTask::vt }, NULL }, &unk_FFF7D180 }, | |
{ { { &KCacheMaintenanceHelperTask::vt }, NULL }, &unk_FFF7D2E0 }, | |
{ { { &KCacheMaintenanceHelperTask::vt }, NULL }, &unk_FFF7D230 }, | |
{ { { &KCacheMaintenanceHelperTask::vt }, &unk_FFF701A4 }, &unk_FFF7D390 } | |
} | |
}; | |
KTlbMaintenanceHelper g_tlbMaintenanceHelper = | |
{ | |
{ &unk_FFF7BB5C, &unk_FFF78D0C, &unk_FFF75C4C, &unk_FFF7834C }, | |
{ | |
{ { &KTlbMaintenanceHelperImpl::vt }, NULL, 4282953728u, KTLBMAINTOP_NONE }, | |
{ { &KTlbMaintenanceHelperImpl::vt }, NULL, 0u, KTLBMAINTOP_NONE }, | |
{ { &KTlbMaintenanceHelperImpl::vt }, NULL, 4282953728u, KTLBMAINTOP_NONE }, | |
{ { &KTlbMaintenanceHelperImpl::vt }, NULL, 4282953728u, KTLBMAINTOP_NONE } | |
} | |
}; | |
KAsidManager g_asidManager = { { 4294967295u, 511u, 0u, 0u, 0u, 0u, 0u, 0u }, { NULL, 0, 0 }, 41u }; | |
KLevel2TranslationTableAllocator g_level2TtblAllocator = | |
{ | |
(KLevel2TranslationTable *)0xEE124800, | |
&unk_EE041000, | |
3992977408u, | |
33554432u, | |
{ NULL, 0, 0 }, | |
2u | |
}; | |
KPerformanceCounterControlHelper g_perfCounterControlHelper = | |
{ | |
{ &KPerformanceCounterControlHelper::vt }, | |
{ false, false, false, false }, | |
0u | |
}; | |
KDmaChannel g_dmaChannels[8] = | |
{ | |
{ | |
{ { &KDmaChannel::vt }, NULL }, | |
{ &KDmaChannel::vt_WorkerTask, NULL }, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
0u, | |
0u, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
0u, | |
'\0', | |
NULL, | |
NULL | |
}, | |
{ 0u, false, 0u, 0u, NULL }, | |
{ 0u, false, 0u, 0u, NULL }, | |
NULL, | |
0u, | |
{ | |
0, | |
NULL, | |
NULL, | |
NULL, | |
{ NULL, NULL }, | |
'\0', | |
false, | |
NULL, | |
NULL, | |
NULL, | |
{ 0u, 0u } | |
}, | |
'\xFF', | |
KDMACHANSTATE_STOPPED, | |
false, | |
false, | |
false, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
0 | |
}, | |
NULL, | |
{ NULL, 0, 0 } | |
}, | |
{ | |
{ { &KDmaChannel::vt }, NULL }, | |
{ &KDmaChannel::vt_WorkerTask, NULL }, | |
(KDmaChannelEventHandler *)0xFFF3305C, | |
&unk_FFF8C820, | |
&unk_FFF79B90, | |
&unk_FFF79B90, | |
{ 128, { 0, 0, 128 }, { 0, 0, 128 } }, | |
{ 128, { 128, 0, 128 }, { 128, 0, 128 } }, | |
{ | |
{ '\xFF', '\x0F', 128, 0, 128, 0 }, | |
{ '\x04', '\x04', 64, 128, 64, 128 }, | |
794319040u, | |
271720448u, | |
false, | |
true, | |
false, | |
true, | |
true, | |
true, | |
0u, | |
'\x01', | |
(KDmaAddress *)0xFFF300AC, | |
(KDmaAddress *)0xFFF300C0 | |
}, | |
{ 794319040u, false, 268454080u, 268454080u, &unk_FFF79B90 }, | |
{ 271720448u, true, 518135808u, 518135808u, &unk_FFF79B90 }, | |
(u8 *)0xFFF2F400, | |
536794112u, | |
{ | |
256, | |
(u8 *)0xFFF2F400, | |
(u8 *)0xFFF2F500, | |
(u8 *)0xFFF2F42B, | |
{ (u8 *)0xFFF2F41C, NULL }, | |
'\0', | |
false, | |
(u8 *)0xFFF2F408, | |
(u8 *)0xFFF2F400, | |
(u8 *)0xFFF2F41C, | |
{ 0u, 0u } | |
}, | |
'\x01', | |
KDMACHANSTATE_STOPPED, | |
false, | |
false, | |
true, | |
{ | |
{ | |
&KDmaProgram::vt, | |
(KDmaBlockBase *)0xFFF30440, | |
(KDmaBlockBase *)0xFFF30220, | |
(KDmaBlockBase *)0xFFF30480, | |
128, | |
0, | |
0, | |
KDMABLOCKTYPE_PROGRAM, | |
'\x06', | |
KDMADIRECTION_BOTH, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 128, { 128, 0, 128 }, { 128, 0, 128 } }, | |
1 | |
}, | |
{ | |
{ | |
&KDmaDataUnitBlock::vt, | |
NULL, | |
NULL, | |
NULL, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_BODY, | |
'\x01', | |
KDMADIRECTION_BOTH, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 64, { 64, 0, 64 }, { 64, 0, 64 } }, | |
0 | |
}, | |
{ '\x04', '\x10', '\x01', '\xFF' }, | |
{ '\x04', '\x10', '\x01', '\xFF' }, | |
{ '\x04', '\x10', '\x01', '\xFF' }, | |
{ '\x04', '\x10', '\x01', '\xFF' } | |
}, | |
{ | |
{ | |
&KDmaSmallerBurstBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF30150, | |
NULL, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_BODY, | |
'\x02', | |
KDMADIRECTION_SRC, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\x02', | |
'\x01', | |
'\0', | |
{ 64, { 64, 0, 64 }, { 64, 0, 64 } }, | |
1 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerBurstBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF301A0, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_BODY, | |
'\x03', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaSmallerTransferBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF301A0, | |
NULL, | |
128, | |
0, | |
0, | |
KDMABLOCKTYPE_BODY, | |
'\x04', | |
KDMADIRECTION_SRC, | |
KDMADIRECTION_SRC, | |
'\x02', | |
'\x02', | |
'\x01', | |
'\0', | |
{ 128, { 128, 0, 128 }, { 128, 0, 128 } }, | |
2 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerTransferBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF30220, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_BODY, | |
'\x05', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaDataUnitBlock::vt, | |
NULL, | |
NULL, | |
NULL, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\x01', | |
KDMADIRECTION_BOTH, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\x04', '\x10', '\x01', '\xFF' }, | |
{ '\x04', '\x10', '\x01', '\xFF' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
&KDmaDataUnitBlock::vt, | |
NULL, | |
NULL, | |
NULL, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_EPILOGUE, | |
'\x01', | |
KDMADIRECTION_BOTH, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\x04', '\x10', '\x01', '\xFF' }, | |
{ '\x04', '\x10', '\x01', '\xFF' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
&KDmaSmallerBurstBlock::vt, | |
(KDmaBlockBase *)0xFFF302A0, | |
(KDmaBlockBase *)0xFFF30150, | |
NULL, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\x02', | |
KDMADIRECTION_SRC, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\x02', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaSmallerBurstBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF30150, | |
(KDmaBlockBase *)0xFFF302F0, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_EPILOGUE, | |
'\x02', | |
KDMADIRECTION_SRC, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerBurstBlock::vt, | |
(KDmaBlockBase *)0xFFF30340, | |
(KDmaBlockBase *)0xFFF301A0, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\x03', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerBurstBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF301A0, | |
(KDmaBlockBase *)0xFFF30380, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_EPILOGUE, | |
'\x03', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaSmallerTransferBlock::vt, | |
(KDmaBlockBase *)0xFFF30340, | |
(KDmaBlockBase *)0xFFF301A0, | |
NULL, | |
128, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\x04', | |
KDMADIRECTION_SRC, | |
KDMADIRECTION_NONE, | |
'\x02', | |
'\x02', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaSmallerTransferBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF301A0, | |
(KDmaBlockBase *)0xFFF30380, | |
128, | |
0, | |
0, | |
KDMABLOCKTYPE_EPILOGUE, | |
'\x04', | |
KDMADIRECTION_SRC, | |
KDMADIRECTION_SRC, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerTransferBlock::vt, | |
(KDmaBlockBase *)0xFFF30440, | |
(KDmaBlockBase *)0xFFF30220, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\x05', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerTransferBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF30220, | |
(KDmaBlockBase *)0xFFF30480, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_EPILOGUE, | |
'\x05', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x01', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
128 | |
}, | |
(KDmaProgram *)0xFFF30110, | |
{ NULL, 0, 0 } | |
}, | |
{ | |
{ { &KDmaChannel::vt }, NULL }, | |
{ &KDmaChannel::vt_WorkerTask, NULL }, | |
(KDmaChannelEventHandler *)0xFFF3305C, | |
&unk_FFF8C808, | |
&unk_FFF79B90, | |
&unk_FFF79B90, | |
{ 128, { 0, 0, 128 }, { 0, 0, 128 } }, | |
{ 128, { 128, 0, 128 }, { 128, 0, 128 } }, | |
{ | |
{ '\x04', '\x04', 64, 128, 64, 128 }, | |
{ '\xFF', '\x0F', 128, 0, 128, 0 }, | |
271720448u, | |
794316960u, | |
true, | |
false, | |
true, | |
false, | |
true, | |
true, | |
0u, | |
'\x02', | |
(KDmaAddress *)0xFFF305D4, | |
(KDmaAddress *)0xFFF305E8 | |
}, | |
{ 271720448u, true, 518135808u, 518135808u, &unk_FFF79B90 }, | |
{ 794316960u, false, 268452000u, 268452000u, &unk_FFF79B90 }, | |
(u8 *)0xFFF2F500, | |
536794368u, | |
{ | |
256, | |
(u8 *)0xFFF2F500, | |
(u8 *)0xFFF2F600, | |
(u8 *)0xFFF2F52B, | |
{ (u8 *)0xFFF2F51C, NULL }, | |
'\0', | |
false, | |
(u8 *)0xFFF2F508, | |
(u8 *)0xFFF2F500, | |
(u8 *)0xFFF2F51C, | |
{ 0u, 0u } | |
}, | |
'\x02', | |
KDMACHANSTATE_STOPPED, | |
false, | |
false, | |
true, | |
{ | |
{ | |
&KDmaProgram::vt, | |
(KDmaBlockBase *)0xFFF30968, | |
(KDmaBlockBase *)0xFFF30748, | |
(KDmaBlockBase *)0xFFF309A8, | |
128, | |
0, | |
0, | |
KDMABLOCKTYPE_PROGRAM, | |
'\x06', | |
KDMADIRECTION_BOTH, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 128, { 128, 0, 128 }, { 128, 0, 128 } }, | |
1 | |
}, | |
{ | |
{ | |
&KDmaDataUnitBlock::vt, | |
NULL, | |
NULL, | |
NULL, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_BODY, | |
'\x01', | |
KDMADIRECTION_BOTH, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 64, { 64, 0, 64 }, { 64, 0, 64 } }, | |
0 | |
}, | |
{ '\x04', '\x10', '\x01', '\0' }, | |
{ '\x04', '\x10', '\x01', '\0' }, | |
{ '\x04', '\x10', '\x01', '\0' }, | |
{ '\x04', '\x10', '\x01', '\0' } | |
}, | |
{ | |
{ | |
&KDmaSmallerBurstBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF30678, | |
NULL, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_BODY, | |
'\x02', | |
KDMADIRECTION_DST, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\x01', | |
'\x02', | |
'\0', | |
{ 64, { 64, 0, 64 }, { 64, 0, 64 } }, | |
1 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerBurstBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF306C8, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_BODY, | |
'\x03', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaSmallerTransferBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF306C8, | |
NULL, | |
128, | |
0, | |
0, | |
KDMABLOCKTYPE_BODY, | |
'\x04', | |
KDMADIRECTION_DST, | |
KDMADIRECTION_DST, | |
'\x01', | |
'\x01', | |
'\x02', | |
'\0', | |
{ 128, { 128, 0, 128 }, { 128, 0, 128 } }, | |
2 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerTransferBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF30748, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_BODY, | |
'\x05', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaDataUnitBlock::vt, | |
NULL, | |
NULL, | |
NULL, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\x01', | |
KDMADIRECTION_BOTH, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\x04', '\x10', '\x01', '\0' }, | |
{ '\x04', '\x10', '\x01', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
&KDmaDataUnitBlock::vt, | |
NULL, | |
NULL, | |
NULL, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_EPILOGUE, | |
'\x01', | |
KDMADIRECTION_BOTH, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\x04', '\x10', '\x01', '\0' }, | |
{ '\x04', '\x10', '\x01', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
&KDmaSmallerBurstBlock::vt, | |
(KDmaBlockBase *)0xFFF307C8, | |
(KDmaBlockBase *)0xFFF30678, | |
NULL, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\x02', | |
KDMADIRECTION_DST, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\x01', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaSmallerBurstBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF30678, | |
(KDmaBlockBase *)0xFFF30818, | |
64, | |
0, | |
0, | |
KDMABLOCKTYPE_EPILOGUE, | |
'\x02', | |
KDMADIRECTION_DST, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerBurstBlock::vt, | |
(KDmaBlockBase *)0xFFF30868, | |
(KDmaBlockBase *)0xFFF306C8, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\x03', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerBurstBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF306C8, | |
(KDmaBlockBase *)0xFFF308A8, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_EPILOGUE, | |
'\x03', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaSmallerTransferBlock::vt, | |
(KDmaBlockBase *)0xFFF30868, | |
(KDmaBlockBase *)0xFFF306C8, | |
NULL, | |
128, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\x04', | |
KDMADIRECTION_DST, | |
KDMADIRECTION_NONE, | |
'\x01', | |
'\x01', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaSmallerTransferBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF306C8, | |
(KDmaBlockBase *)0xFFF308A8, | |
128, | |
0, | |
0, | |
KDMABLOCKTYPE_EPILOGUE, | |
'\x04', | |
KDMADIRECTION_DST, | |
KDMADIRECTION_DST, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerTransferBlock::vt, | |
(KDmaBlockBase *)0xFFF30968, | |
(KDmaBlockBase *)0xFFF30748, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\x05', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
&KDmaLargerTransferBlock::vt, | |
NULL, | |
(KDmaBlockBase *)0xFFF30748, | |
(KDmaBlockBase *)0xFFF309A8, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_EPILOGUE, | |
'\x05', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\x02', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
128 | |
}, | |
(KDmaProgram *)0xFFF30638, | |
{ NULL, 0, 0 } | |
}, | |
{ | |
{ { &KDmaChannel::vt }, NULL }, | |
{ &KDmaChannel::vt_WorkerTask, NULL }, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
0u, | |
0u, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
0u, | |
'\0', | |
NULL, | |
NULL | |
}, | |
{ 0u, false, 0u, 0u, NULL }, | |
{ 0u, false, 0u, 0u, NULL }, | |
NULL, | |
0u, | |
{ | |
0, | |
NULL, | |
NULL, | |
NULL, | |
{ NULL, NULL }, | |
'\0', | |
false, | |
NULL, | |
NULL, | |
NULL, | |
{ 0u, 0u } | |
}, | |
'\xFF', | |
KDMACHANSTATE_STOPPED, | |
false, | |
false, | |
false, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
0 | |
}, | |
NULL, | |
{ NULL, 0, 0 } | |
}, | |
{ | |
{ { &KDmaChannel::vt }, NULL }, | |
{ &KDmaChannel::vt_WorkerTask, NULL }, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
0u, | |
0u, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
0u, | |
'\0', | |
NULL, | |
NULL | |
}, | |
{ 0u, false, 0u, 0u, NULL }, | |
{ 0u, false, 0u, 0u, NULL }, | |
NULL, | |
0u, | |
{ | |
0, | |
NULL, | |
NULL, | |
NULL, | |
{ NULL, NULL }, | |
'\0', | |
false, | |
NULL, | |
NULL, | |
NULL, | |
{ 0u, 0u } | |
}, | |
'\xFF', | |
KDMACHANSTATE_STOPPED, | |
false, | |
false, | |
false, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
0 | |
}, | |
NULL, | |
{ NULL, 0, 0 } | |
}, | |
{ | |
{ { &KDmaChannel::vt }, NULL }, | |
{ &KDmaChannel::vt_WorkerTask, NULL }, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
0u, | |
0u, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
0u, | |
'\0', | |
NULL, | |
NULL | |
}, | |
{ 0u, false, 0u, 0u, NULL }, | |
{ 0u, false, 0u, 0u, NULL }, | |
NULL, | |
0u, | |
{ | |
0, | |
NULL, | |
NULL, | |
NULL, | |
{ NULL, NULL }, | |
'\0', | |
false, | |
NULL, | |
NULL, | |
NULL, | |
{ 0u, 0u } | |
}, | |
'\xFF', | |
KDMACHANSTATE_STOPPED, | |
false, | |
false, | |
false, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
0 | |
}, | |
NULL, | |
{ NULL, 0, 0 } | |
}, | |
{ | |
{ { &KDmaChannel::vt }, NULL }, | |
{ &KDmaChannel::vt_WorkerTask, NULL }, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
0u, | |
0u, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
0u, | |
'\0', | |
NULL, | |
NULL | |
}, | |
{ 0u, false, 0u, 0u, NULL }, | |
{ 0u, false, 0u, 0u, NULL }, | |
NULL, | |
0u, | |
{ | |
0, | |
NULL, | |
NULL, | |
NULL, | |
{ NULL, NULL }, | |
'\0', | |
false, | |
NULL, | |
NULL, | |
NULL, | |
{ 0u, 0u } | |
}, | |
'\xFF', | |
KDMACHANSTATE_STOPPED, | |
false, | |
false, | |
false, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
0 | |
}, | |
NULL, | |
{ NULL, 0, 0 } | |
}, | |
{ | |
{ { &KDmaChannel::vt }, NULL }, | |
{ &KDmaChannel::vt_WorkerTask, NULL }, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
{ | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
{ '\0', '\0', 0, 0, 0, 0 }, | |
0u, | |
0u, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
0u, | |
'\0', | |
NULL, | |
NULL | |
}, | |
{ 0u, false, 0u, 0u, NULL }, | |
{ 0u, false, 0u, 0u, NULL }, | |
NULL, | |
0u, | |
{ | |
0, | |
NULL, | |
NULL, | |
NULL, | |
{ NULL, NULL }, | |
'\0', | |
false, | |
NULL, | |
NULL, | |
NULL, | |
{ 0u, 0u } | |
}, | |
'\xFF', | |
KDMACHANSTATE_STOPPED, | |
false, | |
false, | |
false, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
}, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' }, | |
{ '\0', '\0', '\0', '\0' } | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
{ | |
{ | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
0, | |
0, | |
0, | |
KDMABLOCKTYPE_PROLOGUE, | |
'\0', | |
KDMADIRECTION_NONE, | |
KDMADIRECTION_NONE, | |
'\0', | |
'\0', | |
'\0', | |
'\0', | |
{ 0, { 0, 0, 0 }, { 0, 0, 0 } }, | |
0 | |
} | |
}, | |
0 | |
}, | |
NULL, | |
{ NULL, 0, 0 } | |
} | |
}; | |
KDmaConfig *g_dmaConfigs[8] = | |
{ | |
NULL, | |
(KDmaConfig *)0xFFF30080, | |
(KDmaConfig *)0xFFF305A8, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
NULL | |
}; | |
KSlabHeap g_linkedListNodeSlabHeap = { &unk_FFF9967C, &unk_FFF95458, 51280u, 12u }; | |
KObjectNameLinkedList g_objectNameList = { 2u, { &unk_FFF95A64, &unk_FFF97684 } }; | |
bool g_isThreadLocalPageVaFree[126] = | |
{ | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
true, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
false, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true, | |
true | |
}; | |
KCpuTimeLimiterMode0 g_cpuTimeLimiterMode0 = | |
{ | |
{ | |
{ &KCpuTimeLimiterMode0::vt, NULL, 0LL }, | |
(KScheduler *)0xFFFDA0C8, | |
0u, | |
false | |
}, | |
1LL, | |
0u, | |
0u, | |
0u, | |
0u | |
}; | |
KCpuTimeLimiterMode1 g_cpuTimeLimiterMode1 = | |
{ | |
{ | |
{ &KCpuTimeLimiterMode1::vt, NULL, 0LL }, | |
(KScheduler *)0xFFFDA0C8, | |
0u, | |
false | |
}, | |
1LL | |
}; | |
KPxiBufferManager g_pxiBufferManager = | |
{ | |
{ | |
{ &unk_FFF7DB20, 134422528u, 300u }, | |
{ NULL, 134259968u, 256u }, | |
{ NULL, 135065600u, 32u }, | |
{ NULL, 134537216u, 72u }, | |
{ NULL, 67125120u, 24u }, | |
{ NULL, 67125064u, 24u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u }, | |
{ NULL, 0u, 0u } | |
}, | |
{ NULL, 0, 0 } | |
}; | |
KSupervisorPageTable g_supervisorPageTable = | |
{ | |
{ | |
{ NULL, 0, 0 }, | |
{ 0, 0, 0, 0 }, | |
{ { 335u, { &unk_FFF955F0, &unk_FFF9C2A4 } } }, | |
0u, | |
0u, | |
0u, | |
0u, | |
true, | |
false, | |
1073741824u, | |
4294963200u, | |
0u, | |
0u, | |
12288u, | |
(u32 *)0xFFFF2000 | |
} | |
}; | |
KMemoryManager g_memoryManager = | |
{ | |
{ | |
{ (KPageHeapBlock *)0xE3000000, (KPageHeapBlock *)0xE3000000 }, | |
3758096384u, | |
130023424u, | |
{ 138367042u, 2224196488u, 1130866005u, 2214765377u } | |
}, | |
{ | |
{ (KPageHeapBlock *)0xE8C52000, (KPageHeapBlock *)0xE8C52000 }, | |
3888119808u, | |
104857600u, | |
{ 732773267u, 2641404568u, 63272552u, 3895632972u } | |
}, | |
{ | |
{ (KPageHeapBlock *)0xEE125000, (KPageHeapBlock *)0xEF64B000 }, | |
3992977408u, | |
33554432u, | |
{ 4074765376u, 815189423u, 263563535u, 1438498989u } | |
}, | |
{ | |
&g_memoryManager, | |
3758096384u, | |
65536u, | |
(u32 *)0xEE000000, | |
745472u, | |
0u, | |
{ NULL, 0, 0 } | |
} | |
}; | |
KInterruptManager g_interruptManager = | |
{ | |
{ | |
{ | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ &g_perfCounterControlHelper, false, false, 0u }, | |
{ &g_terminationHelper, false, false, 0u }, | |
{ &g_systemControlHelper, false, false, 0u }, | |
{ &g_cacheMaintenanceHelper, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFFD10C8, false, false, 0u }, | |
{ &g_vfpRegisterDumpHelper, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFF2F248, false, false, 0u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u } | |
}, | |
{ | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ &g_perfCounterControlHelper, false, false, 0u }, | |
{ &g_terminationHelper, false, false, 0u }, | |
{ &g_systemControlHelper, false, false, 0u }, | |
{ &g_cacheMaintenanceHelper, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFFDA0C8, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFF2F188, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFF2F258, false, false, 0u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ &g_hardwareTimer, true, false, 0u }, | |
{ &g_hardwareTimer, false, false, 0u }, | |
{ NULL, false, false, 15u } | |
}, | |
{ | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ &g_perfCounterControlHelper, false, false, 0u }, | |
{ &g_terminationHelper, false, false, 0u }, | |
{ &g_systemControlHelper, false, false, 0u }, | |
{ &g_cacheMaintenanceHelper, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFFE30C8, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFF2F190, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFF2F268, false, false, 0u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u } | |
}, | |
{ | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ &g_perfCounterControlHelper, false, false, 0u }, | |
{ &g_terminationHelper, false, false, 0u }, | |
{ &g_systemControlHelper, false, false, 0u }, | |
{ &g_cacheMaintenanceHelper, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFFEC0C8, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFF2F198, false, false, 0u }, | |
{ (KInterruptHandler *)0xFFF2F278, false, false, 0u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u }, | |
{ NULL, false, false, 15u } | |
} | |
}, | |
{ | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ &unk_FFF70744, true, false, 0u }, | |
{ &unk_FFF7076C, true, false, 0u }, | |
{ &unk_FFF70794, true, false, 0u }, | |
{ &unk_FFF707BC, true, false, 0u }, | |
{ &unk_FFF707E4, true, false, 0u }, | |
{ &unk_FFF7080C, true, true, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ &g_dmaManager, false, false, 0u }, | |
{ &g_dmaManager, true, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ &unk_FFF70B2C, true, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ &unk_FFF7062C, true, false, 0u }, | |
{ &unk_FFF70654, true, false, 0u }, | |
{ &unk_FFF7049C, true, false, 0u }, | |
{ &unk_FFF709C4, true, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ &unk_FFF70064, true, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, true, false, 0u }, | |
{ NULL, true, false, 0u }, | |
{ &unk_FFF701A4, true, false, 0u }, | |
{ &unk_FFF701CC, true, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ &unk_FFF70A3C, true, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ &unk_FFF701F4, true, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ &unk_FFF70474, true, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, true, false, 0u }, | |
{ &unk_FFF70A8C, true, false, 0u }, | |
{ &unk_FFF7044C, true, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ &unk_FFF7008C, true, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u }, | |
{ NULL, false, false, 0u } | |
}, | |
{ NULL, 0, 0 } | |
}; | |
KHardwareTimer g_hardwareTimer = | |
{ | |
{ { &KHardwareTimer::vt }, &unk_FFF7080C }, | |
3u, | |
3u, | |
{ &KDummyTimerTask::vt, &unk_FFF74FD8, 0LL }, | |
{ NULL, 0 } | |
}; | |
KDmaManager g_dmaManager = | |
{ | |
{ { &KDmaManager::vt }, &unk_FFF70B2C }, | |
{ &KDmaManager::vt_KDmaChannelEventHandler }, | |
{ false, true, true, false, false, false, false, false }, | |
{ false, false, false, false, false, false, false, false } | |
}; | |
KPerformanceCounterManager g_perfCounterMgr = | |
{ | |
{ &KPerformanceCounterManager::vt }, | |
{ { 0u, 0u, 0u }, { 0u, 0u, 0u }, { 0u, 0u, 0u }, { 0u, 0u, 0u } }, | |
{ 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u }, | |
false | |
}; | |
KWorkerTaskManager g_workerTaskManager[2] = | |
{ | |
{ KWORKERTYPE_HIGH_PRIO, NULL, NULL, false, &unk_FFF7D440 }, | |
{ KWORKERTYPE_LOW_PRIO, NULL, NULL, false, &unk_FFF7D4F0 } | |
}; | |
KFiqHelper g_fiqHelper = { { { &KFiqHelper::vt }, NULL }, NULL, false, false }; | |
KObjectAllocator g_dmaObjectAllocator = | |
{ | |
{ { 2u, { &unk_FFF9CB5C, &unk_FFF9BBCC } }, { NULL, 0, 0 } }, | |
2, | |
{ &unk_FFF8C838, &unk_FFF8C808, 384u, 24u } | |
}; | |
KObjectAllocator g_semaphoreAllocator = | |
{ | |
{ { 47u, { &unk_FFF95A4C, &unk_FFF9C400 } }, { NULL, 0, 0 } }, | |
47, | |
{ &unk_FFF747EC, &unk_FFF73FD8, 3656u, 44u } | |
}; | |
KObjectAllocator g_sharedMemoryAllocator = | |
{ | |
{ { 11u, { &unk_FFF9724C, &unk_FFF9B908 } }, { NULL, 0, 0 } }, | |
12, | |
{ &unk_FFF8CB40, &unk_FFF8C988, 2520u, 40u } | |
}; | |
KObjectAllocator g_resourceLimitAllocator = | |
{ | |
{ { 4u, { &unk_FFF95C68, &unk_FFF95C8C } }, { NULL, 0, 0 } }, | |
4, | |
{ &unk_FFF93D80, &unk_FFF93BB0, 584u, 116u } | |
}; | |
KObjectAllocator g_addressArbiterAllocator = | |
{ | |
{ { 40u, { &unk_FFF959F8, &unk_FFF9CB50 } }, { NULL, 0, 0 } }, | |
40, | |
{ &unk_FFF94118, &unk_FFF93DF8, 1024u, 20u } | |
}; | |
KObjectAllocator g_portAllocator = | |
{ | |
{ { 136u, { &unk_FFF95A58, &unk_FFF9C6A0 } }, { NULL, 0, 0 } }, | |
136, | |
{ &unk_FFF8C340, &unk_FFF89D00, 11016u, 72u } | |
}; | |
KObjectAllocator g_eventAllocator = | |
{ | |
{ { 157u, { &unk_FFF95AAC, &unk_FFF97B1C } }, { NULL, 0, 0 } }, | |
159, | |
{ &unk_FFF71860, &_slabheaps_start, 12600u, 40u } | |
}; | |
KObjectAllocator g_mutexAllocator = | |
{ | |
{ { 15u, { &unk_FFF95AB8, &unk_FFF9A030 } }, { NULL, 0, 0 } }, | |
15, | |
{ &unk_FFF733CC, &unk_FFF73138, 3744u, 44u } | |
}; | |
KObjectAllocator g_timerAllocator = | |
{ | |
{ { 15u, { &unk_FFF96D90, &unk_FFF9946C } }, { NULL, 0, 0 } }, | |
15, | |
{ &unk_FFF751A4, &unk_FFF74E20, 3600u, 60u } | |
}; | |
KObjectAllocator g_debugAllocator = | |
{ | |
{ | |
{ | |
0u, | |
{ | |
(KAutoObjectLinkedListNode *)0xFFF3328C, | |
(KAutoObjectLinkedListNode *)0xFFF3328C | |
} | |
}, | |
{ NULL, 0, 0 } | |
}, | |
0, | |
{ &unk_FFF8D360, &unk_FFF8D360, 480u, 160u } | |
}; | |
KObjectAllocator g_threadAllocator = | |
{ | |
{ { 189u, { &unk_FFF95464, &unk_FFF9BAB8 } }, { NULL, 0, 0 } }, | |
192, | |
{ &unk_FFF84870, &unk_FFF7CEC0, 52800u, 176u } | |
}; | |
KObjectAllocator g_codeSetAllocator = | |
{ | |
{ { 40u, { &unk_FFF95530, &unk_FFF99AF0 } }, { NULL, 0, 0 } }, | |
40, | |
{ &unk_FFF95198, &unk_FFF941F8, 4704u, 100u } | |
}; | |
KObjectAllocator g_processAllocator = | |
{ | |
{ { 40u, { &unk_FFF955C0, &unk_FFF9C0AC } }, { NULL, 0, 0 } }, | |
40, | |
{ &unk_FFF7BDB0, &unk_FFF75C30, 29328u, 624u } | |
}; | |
KObjectAllocator g_sessionAllocator = | |
{ | |
{ { 181u, { &unk_FFF95AA0, &unk_FFF9CC1C } }, { NULL, 0, 0 } }, | |
197, | |
{ &unk_FFF90B94, &unk_FFF8D540, 26224u, 76u } | |
}; | |
KSlabHeap g_blockInfoSlabHeap = { &unk_FFFA21D8, &unk_FFFA1CA8, 4808u, 8u }; | |
KSlabHeap g_eventInfoSlabHeap = { &unk_FFFAC868, &unk_FFFAC868, 3752u, 56u }; | |
KSlabHeap g_objectNameSlabHeap = { &unk_FFFABC30, &unk_FFFABC10, 112u, 16u }; | |
KSlabHeap g_memoryBlockSlabHeap = { &unk_FFFA59DC, &unk_FFFA2F70, 34464u, 20u }; | |
KSlabHeap g_threadLocalPageSlabHeap = { &unk_FFFAB850, &unk_FFFAB610, 1536u, 24u }; | |
KSlabHeap g_debugThreadSlabHeap = { &unk_FFFABC80, &unk_FFFABC80, 3048u, 24u }; | |
_UNKNOWN _slabheaps_start; // weak | |
volatile CoreLinkL2C310 L2C; | |
volatile I2cRegisters I2C2; | |
vu32 GX_VRAM_BANKS_DISABLE; | |
vu16 PDN_CNT; | |
vu32 PDN_GPU_CNT; | |
vu16 PDN_FCRAM_CNT; | |
volatile PxiRegisters PXI; | |
volatile HidRegisters HID; | |
volatile LcdAblRegisters LCD_ABL_TOP; | |
volatile LcdAblRegisters LCD_ABL_BOT; | |
volatile Config11Registers CONFIG11; | |
volatile CoreLinkDma330 CDMA; | |
KCoreLocalPseudoRegion g_coreLocalRegions[4]; | |
volatile Mp11PrivateMemRegion MPCORE; | |
KCoreLocalPseudoRegion current; | |
_UNKNOWN KernStackL2Tables; // weak | |
//----- (1FFAF000) -------------------------------------------------------- | |
void crt0::Cpu0GetInitSpValues() | |
{ | |
; | |
} | |
//----- (1FFAF01C) -------------------------------------------------------- | |
void crt0::Cpu1GetInitSpValues() | |
{ | |
; | |
} | |
//----- (1FFAF034) -------------------------------------------------------- | |
void crt0::Cpu2GetInitSpValues() | |
{ | |
; | |
} | |
//----- (1FFAF04C) -------------------------------------------------------- | |
void crt0::Cpu3GetInitSpValues() | |
{ | |
; | |
} | |
//----- (1FFAF064) -------------------------------------------------------- | |
void __noreturn _start(void) | |
{ | |
s32 coreId; // r4 | |
__asm { CPSID AIF } | |
j_crt0::SetArm11ControlRegs(); | |
coreId = __mrc(15, 0, 0, 0, 5) & 3; | |
crt0::stackSelectors[coreId](); | |
__asm | |
{ | |
CPS #0x1F | |
CPS #0x12 | |
MSR SPSR_cxsf, #0 | |
CPS #0x11 | |
MSR SPSR_cxsf, #0 | |
CPS #0x17 | |
MSR SPSR_cxsf, #0 | |
CPS #0x1B | |
MSR SPSR_cxsf, #0 | |
CPS #0x13 | |
MSR SPSR_cxsf, #0 | |
} | |
crt0::InitCpu(coreId); | |
__asm { CPS #0x13 } | |
crt0::CoreSync(coreId); | |
HorizonKernelMain(); | |
} | |
// 1FFAF148: using guessed type int (*crt0::stackSelectors[4])(); | |
//----- (1FFAF168) -------------------------------------------------------- | |
void __fastcall crt0::CoreSync(s32 coreId) | |
{ | |
_DWORD *v2; // r6 | |
int v3; // r0 | |
char cfgr; // r1 | |
char v5; // r0 | |
int numInterruptLines; // r0 | |
int v7; // r1 | |
int v8; // r4 | |
u32 *v9; // r4 | |
u32 v10; // r0 | |
BOOL has4Cores; // r11 | |
unsigned int i; // r0 | |
unsigned int v13; // r4 | |
u8 bootenv; // r0 | |
__int16 *j; // r0 | |
__int16 v16; // t1 | |
int *v17; // r0 | |
int v18; // t1 | |
int v19; // r0 | |
int v20; // r1 | |
int v21; // r2 | |
int v22; // r0 | |
crt0::SetVfpAccessibleToUser(); | |
__mcr(14, 0, __mrc(14, 0, 0, 1, 0) | 0x1000, 0, 1, 0);// DSCR |= User mode access to comms channel disabled. | |
__mcr(14, 7, __mrc(14, 7, 1, 0, 0) & ~3u | 1, 1, 0, 0);// | |
// according to DDI01001, this is the | |
// Jazelle OS Control register. Disable Jazelle. | |
v2 = (_DWORD *)((unsigned int)&MPCORE.gicd & 0xFFFFE000); | |
MPCORE.gicd.icpendr[0] = 0xFFFFFFFF; | |
*(_DWORD *)(((unsigned int)&MPCORE.gicd & 0xFFFFE000) + 0x100) = 1;// activate gicc interface | |
if ( coreId ) | |
{ | |
*(_DWORD *)(((unsigned int)&MPCORE.gicd & 0xFFFFE000) + 0x1F00) = coreId | 0x10000;// send SGI <coreId> to core0 | |
do | |
{ | |
__wfi(); | |
v3 = v2[67]; | |
v2[68] = v3; | |
} | |
while ( v3 != (((unsigned __int8)(coreId - 1) << 10) | 4) );// wait for previous core to have booted up | |
cfgr = MPCORE.scu.cfgr; | |
if ( (cfgr & 3) + 1 > coreId + 1 ) // if there's another core | |
*(_DWORD *)(((unsigned int)&MPCORE.gicd & 0xFFFFE000) + 0x1F00) = (1 << (coreId + 1) << 16) | 4;// send SGI 4 | |
// | |
// this isn't reached before all cores except 0 have executed the previous section | |
} | |
else | |
{ | |
numInterruptLines = (MPCORE.gicd.typer & 0x1F) + 1; | |
if ( numInterruptLines > 0 ) | |
{ | |
v7 = numInterruptLines & 1; | |
if ( v7 == 1 ) | |
MPCORE.gicd.icenabler[0] = 0xFFFFFFFF; | |
} | |
else | |
{ | |
v7 = 0; | |
} | |
for ( ; v7 < numInterruptLines; v9[0x61] = 0xFFFFFFFF )// icenabler | |
{ | |
v8 = v7; | |
v7 += 2; | |
v9 = &MPCORE.gicd.ctlr + v8; | |
v9[96] = 0xFFFFFFFF; | |
} | |
MPCORE.gicd.ctlr = 1; | |
v10 = MPCORE.scu.cfgr; | |
has4Cores = (~v10 & 3) == 0; | |
MPCORE.gicd.sgir = 0x20001; // send SGI1 to core1 to wake it up | |
if ( (~v10 & 3) == 0 ) // four cpus | |
{ | |
MPCORE.gicd.sgir = 0x40002; // send SGI2 to core2 to wake it up | |
MPCORE.gicd.sgir = 0x80003; // send SGI3 to core3 to wake it up | |
} | |
for ( i = 0; 0x4230u >> 2 > i; ++i ) // bss clear | |
(&g_vfpRegisterDumpHelper.impls[0].__vftable)[i] = 0; | |
_libc_init_array(); | |
CONFIG11.gpuprot = 0x550; | |
v13 = 0x1FFA0000; | |
bootenv = crt0::FetchArm9Info()[2]; // copy deliver (firmlaunch) args to 0x1FFA1000 | |
if ( (bootenv & 1) != 0 ) | |
{ | |
if ( (bootenv & 6) != 0 ) | |
{ | |
for ( j = (__int16 *)0xE0000000; (unsigned int)j < 0xE0001000; j += 4 ) | |
{ // We were in legacy mode. Copy 2 bytes with a stride of 8. | |
v16 = *j; | |
*(_WORD *)v13 = v16; | |
v13 += 2; | |
} | |
for ( ; v13 < 0x1FFA1000; v13 += 4 ) | |
*(_DWORD *)v13 = 0; | |
} | |
else | |
{ | |
v17 = (int *)0xE0000000; // Non-legacy, normal FCRAM layout | |
do | |
{ | |
v18 = *v17++; | |
*(_DWORD *)v13 = v18; | |
v13 += 4; | |
} | |
while ( v13 < 0x1FFA1000 ); | |
} | |
} | |
else | |
{ | |
do | |
{ | |
*(_DWORD *)v13 = 0; | |
v13 += 4; | |
} | |
while ( v13 < 0x1FFA1000 ); | |
} | |
if ( has4Cores ) | |
{ | |
v19 = 0; | |
do | |
{ | |
__wfi(); | |
v20 = v2[67]; | |
v21 = (unsigned __int16)(v20 & 0x1C00) >> 10; | |
v2[68] = v20; | |
if ( (v20 & 0x3FF) == v21 ) | |
v19 |= 1 << v21; | |
} | |
while ( (~v19 & 0xE) != 0 ); // wait for all other cores to have booted up | |
} | |
else | |
{ | |
do | |
{ | |
__wfi(); | |
v22 = v2[67]; | |
v2[68] = v22; | |
} | |
while ( v22 != 0x401 ); | |
} | |
MPCORE.gicd.sgir = 0x20004; // unblock core1, in turn unblocking core2 then core3 | |
} | |
v2[64] = 0; // disable gicc again | |
v5 = MPCORE.scu.cfgr; | |
if ( (v5 & 3) == coreId ) // last core (core3 or core1) executes this section | |
{ | |
MPCORE.gicd.ctlr = 0; | |
LOBYTE(CONFIG11.cdma_cnt) = 0x10; // mic, bit0: disabled | |
// ntrcard, bit1: disabled | |
// cam0/1, bits2-3: disabled | |
// wifi, bit4: enabled (new in 11.4) | |
// sdio3? (sd card), bit5: disabled | |
} | |
} | |
//----- (1FFAF44C) -------------------------------------------------------- | |
void crt0::SetVfpAccessibleToUser(void) | |
{ | |
__mcr(15, 0, 0xF00000u, 1, 0, 2); | |
__mcr(15, 0, 0xF00000u, 7, 5, 4); | |
_R0 = 0; | |
__asm { VMSR FPEXC, R0 } | |
} | |
//----- (1FFAF464) -------------------------------------------------------- | |
void __fastcall crt0::WaitCycles(u32 numCycles) | |
{ | |
bool v1; // cc | |
do | |
{ | |
v1 = (int)numCycles <= 2; | |
numCycles -= 2; | |
} | |
while ( !v1 ); | |
} | |
//----- (1FFAF474) -------------------------------------------------------- | |
void crt0::SetArm11ControlRegs(void) | |
{ | |
__mcr(15, 0, 0x54078u, 1, 0, 0); | |
__mcr(15, 0, 0xFu, 1, 0, 1); | |
__mcr(15, 0, 0, 7, 5, 4); | |
__mcr(15, 0, 0, 7, 5, 0); | |
__mcr(15, 0, 0, 7, 6, 0); | |
__mcr(15, 0, 0, 7, 10, 4); | |
} | |
//----- (1FFAF4A0) -------------------------------------------------------- | |
void __noreturn crt0::Core23Ep(void) | |
{ | |
int v4; // r4 | |
u32 iar; // r0 | |
__asm { CPSID AIF } | |
__mcr(15, 0, __mrc(15, 0, 15, 12, 0) | 0xFFFF00D, 15, 12, 0);// enable, | |
// no count reg reset on write, | |
// cycle counter reset on write, | |
// Cycle Counter Register counts every 64th processor clock | |
// cycle, evtcount0 = evtcount1 = 0xff (unpredictable) | |
PA_MPCORE.gicc.ctlr = 1; | |
v4 = __mrc(15, 0, 0, 0, 5) & 3; | |
if ( v4 == 3 ) | |
PA_PDN.lgr_cpu_cnt[3] = 1; // clear bit 1 | |
else | |
PA_PDN.lgr_cpu_cnt[2] = 1; | |
do | |
{ | |
__wfi(); | |
iar = PA_MPCORE.gicc.iar; | |
PA_MPCORE.gicc.eoir = iar; | |
} | |
while ( iar != v4 ); | |
_start(); | |
} | |
//----- (1FFAF528) -------------------------------------------------------- | |
void __fastcall DoFcramTrainingUnused(u32 *testPatternLocation, u32 initialNumIterations, u32 numIterationsIncrement) | |
{ | |
u32 v3; // r6 | |
*testPatternLocation = 0x1F3D5B79; // unused function? | |
testPatternLocation[1] = 1; | |
testPatternLocation[2] = 2; | |
testPatternLocation[3] = 3; | |
testPatternLocation[4] = 4; | |
testPatternLocation[5] = 5; | |
testPatternLocation[6] = 6; | |
testPatternLocation[7] = 7; | |
while ( *testPatternLocation != 0x1F3D5B79 ) | |
{ | |
PA_FCRAMCFG.cnt1 = 131075; | |
v3 = initialNumIterations; | |
do | |
--v3; | |
while ( v3 ); | |
PA_FCRAMCFG.cnt1 = 0x20000; | |
initialNumIterations += numIterationsIncrement; | |
} | |
} | |
//----- (1FFAF5A4) -------------------------------------------------------- | |
void __fastcall crt0::PrepareTranslationTables(s32 coreId) | |
{ | |
int v1; // r5 | |
u32 *L1; // r2 | |
u32 *L2_FFF; // r1 | |
u32 *v4; // r4 | |
unsigned int v5; // r5 | |
int v6; // r7 | |
int v7; // r4 | |
unsigned int v8; // r10 | |
unsigned int v9; // r3 | |
unsigned int v10; // r4 | |
int *v11; // r7 | |
bool v12; // cc | |
int v13; // r9 | |
unsigned int v14; // r3 | |
unsigned int v15; // r4 | |
u32 *v16; // r7 | |
bool v17; // cc | |
int v18; // r9 | |
unsigned int *v19; // r4 | |
unsigned int v20; // r3 | |
int v21; // r12 | |
bool v22; // cc | |
unsigned int v23; // r8 | |
unsigned int v24; // r3 | |
unsigned int v25; // r12 | |
int *v26; // r4 | |
bool v27; // cc | |
int v28; // r8 | |
int *v29; // r6 | |
unsigned int v30; // r2 | |
int v31; // r3 | |
int v32; // r12 | |
char *v33; // r3 | |
unsigned int v34; // r9 | |
unsigned int v35; // r12 | |
unsigned int v36; // r11 | |
bool v37; // zf | |
u32 *v38; // r9 | |
bool v39; // cc | |
int v40; // lr | |
int v41; // r3 | |
int v42; // r12 | |
int v43; // r12 | |
int v44; // r8 | |
int v45; // r3 | |
unsigned int v46; // r3 | |
int v47; // r12 | |
unsigned int v48; // r3 | |
unsigned int v49; // r8 | |
unsigned int v50; // r12 | |
int *v51; // r9 | |
bool v52; // cc | |
int v53; // r11 | |
int v54; // r3 | |
unsigned int v55; // r3 | |
unsigned int v56; // r2 | |
int *v57; // r12 | |
bool v58; // cc | |
int v59; // r8 | |
char *v60; // r2 | |
unsigned int v61; // r12 | |
int *v62; // r9 | |
bool v63; // cc | |
int v64; // r10 | |
KLightMutex *v65; // r11 | |
int *v66; // r7 | |
unsigned int v67; // r8 | |
unsigned int v68; // r6 | |
int v69; // r10 | |
unsigned int v70; // r3 | |
unsigned int v71; // r9 | |
int *v72; // r10 | |
bool v73; // cc | |
int v74; // lr | |
int *v75; // r12 | |
bool v76; // cc | |
int v77; // r9 | |
int *v78; // r2 | |
unsigned int v79; // r6 | |
bool v80; // cc | |
u32 *L1Table; // r2 | |
unsigned int v82; // r3 | |
u32 *v83; // r12 | |
bool v84; // cc | |
int v85; // r8 | |
u32 *v86; // r2 | |
u32 *v87; // r12 | |
unsigned int v88; // r3 | |
bool v89; // cc | |
unsigned int v90; // r8 | |
u32 *v91; // r2 | |
unsigned int v92; // r3 | |
u32 *v93; // r12 | |
bool v94; // cc | |
int v95; // r8 | |
u32 *v96; // r2 | |
u32 *v97; // r12 | |
unsigned int v98; // r3 | |
bool v99; // cc | |
unsigned int v100; // r8 | |
unsigned int v101; // r2 | |
u32 v102; // r6 | |
u32 v103; // r7 | |
u32 *v104; // r0 | |
u32 *v105; // r3 | |
unsigned int v106; // r9 | |
bool v107; // cc | |
volatile Mp11PrivateMemRegion *v108; // r2 | |
u32 *v109; // r12 | |
volatile Mp11PrivateMemRegion *v110; // r3 | |
bool v111; // cc | |
unsigned int v112; // r7 | |
char *v113; // r0 | |
u32 *v114; // r1 | |
bool v115; // cc | |
int v116; // r3 | |
v1 = 2048; | |
L1 = crt0::L1TableAddresses[coreId]; | |
L2_FFF = crt0::L2TableAddresses_FFF[coreId]; | |
v4 = L1 - 1; | |
do | |
{ | |
--v1; | |
v4[1] = 0; | |
v4[2] = 0; | |
v4 += 2; | |
} | |
while ( v1 ); | |
v5 = 0x1FFF5000; | |
if ( !coreId ) | |
{ | |
v6 = 0x600; | |
v7 = 0x1FFF4FFC; // kernel stacks mapping? | |
do | |
{ | |
*(_DWORD *)(v7 + 4) = 0; | |
--v6; | |
*(_DWORD *)(v7 + 8) = 0; | |
v7 += 8; | |
} | |
while ( v6 ); | |
} | |
v8 = 0x1F3F0000; | |
L1[0x1FF] = 0x1FF16406; // identity mapping, L1 | |
L1[0x1F3] = 0x1F316406; | |
v9 = 0xD8000000; | |
v10 = 0x18000000; | |
v11 = (int *)(L1 + 3456); | |
do | |
{ | |
v9 += 0x100000; | |
v12 = v9 != 0; | |
v13 = (v10 >> 20 << 20) | 0x16416; | |
if ( v9 ) | |
v12 = v9 < 0xD85FFFFF; | |
v10 += 0x100000; | |
*v11++ = v13; | |
} | |
while ( v12 ); | |
v14 = 0xDF000000; | |
v15 = 0x1F000000; | |
v16 = L1 + 0xDF0; | |
do | |
{ | |
v14 += 0x100000; | |
v17 = v14 != 0; | |
v18 = (v15 >> 20 << 20) | 0x16416; | |
if ( v14 ) | |
v17 = v14 < 0xDF3FFFFF; | |
v15 += 0x100000; | |
*v16++ = v18; | |
} | |
while ( v17 ); | |
v19 = L1 + 0xE00; | |
L1[0xDFF] = 0x1FF16416; | |
v20 = 0xE0000000; // FCRAM | |
v21 = 0x20000000; | |
do | |
{ | |
v20 += 0x100000; | |
v22 = v20 != 0; | |
v23 = v21 & 0xFF000000 | 0x56416; | |
if ( v20 ) | |
v22 = v20 < 0xEFFFFFFF; | |
v21 += 0x100000; | |
*v19++ = v23; | |
} | |
while ( v22 ); | |
v24 = 0xFF400000; // kernel stack area page tables | |
v25 = 0x1FFF5000; | |
v26 = (int *)(L1 + 0xFF4); | |
do | |
{ | |
v24 += 0x100000; | |
v27 = v24 != 0; | |
v28 = (v25 >> 10 << 10) | 1; | |
if ( v24 ) | |
v27 = v24 < 0xFFBFFFFF; | |
v25 += 1024; | |
*v26++ = v28; | |
} | |
while ( v27 ); | |
L1[0xFFF] = ((unsigned int)L2_FFF >> 10 << 10) | 1; | |
v29 = &_dso_handle; | |
v30 = -(int)&HID; | |
if ( (unsigned int)-(int)&HID >= 0x42000 ) | |
v31 = 0x42000; | |
else | |
v31 = -(int)&HID; | |
if ( (int)(((unsigned int)(v31 - 0x90000) >> 16 << 16) + 0x90000) > 0 ) | |
{ | |
v32 = v30 >= 0x42000 ? 270336 : -(int)&HID; | |
v33 = (char *)&_slabheaps_start; // slabheaps | |
v34 = (unsigned int)(v32 + 0xFFF70000) >> 16; | |
v35 = 0x1FFA0000; | |
v36 = (v34 << 16) - 1; | |
v37 = v34 << 16 == 0xFFF70001; | |
v38 = L2_FFF + 0x70; | |
if ( !v37 && v36 >= 0xFFF70000 ) | |
{ | |
do | |
{ | |
v33 += 4096; | |
v39 = v33 != 0; | |
v40 = (HIWORD(v35) << 16) | 0xE415; | |
if ( v33 ) | |
v39 = v36 > (unsigned int)v33; | |
v35 += 4096; | |
*v38++ = v40; | |
} | |
while ( v39 ); | |
} | |
} | |
if ( v30 >= 0x42000 ) | |
{ | |
v41 = 0x42000; | |
v42 = 0x42000; | |
} | |
else | |
{ | |
v41 = -(int)&HID; | |
v42 = -(int)&HID; | |
} | |
if ( (int)(v41 - ((unsigned int)(v42 + 0xFFF70000) >> 16 << 16) + 0xFFF70000) > 0 ) | |
{ | |
v43 = v30 >= -0xFFFBE000 ? -0xFFFBE000 : -(int)&HID; | |
v44 = v43 + 0xFFF70000; | |
v45 = v30 >= -0xFFFBE000 ? -0xFFFBE000 : -(int)&HID; | |
v46 = v45 + 0xFFF70000; | |
v47 = v30 >= -0xFFFBE000 ? -0xFFFBE000 : -(int)&HID; | |
v48 = HIWORD(v46) << 16; | |
v49 = v44 - 1; | |
v50 = ((unsigned int)(v47 + 0xFFF70000) >> 16 << 16) - 0xDFFD0000; | |
v51 = (int *)((char *)L2_FFF + ((v48 & 0xFF000) >> 10)); | |
if ( v48 < v49 ) | |
{ | |
do | |
{ | |
v48 += 4096; | |
v52 = v48 != 0; | |
v53 = (v50 >> 12 << 12) | 0x597; // last <64K of heap | |
if ( v48 ) | |
v52 = v49 > v48; | |
v50 += 4096; | |
*v51++ = v53; | |
} | |
while ( v52 ); | |
} | |
} | |
if ( v30 >= -0xFFFBE000 ) | |
v54 = 0x42000; | |
else | |
v54 = -(int)&HID; | |
v55 = v54 + 0xFFF70000; | |
if ( v30 >= -0xFFFBE000 ) | |
v30 = 0x42000; | |
v56 = v30 + 0xFFF71FFF; | |
v57 = (int *)((char *)L2_FFF + ((v55 & 0xFF000) >> 10)); | |
if ( v55 < v56 ) | |
{ | |
do | |
{ | |
v55 += 4096; | |
v58 = v55 != 0; | |
v59 = (v8 >> 12 << 12) | 0x597; // qtm mem | |
if ( v55 ) | |
v58 = v56 > v55; | |
v8 += 4096; | |
*v57++ = v59; | |
} | |
while ( v58 ); | |
} | |
v60 = (char *)&loc_FFF20000; | |
v61 = 0x1FF80000; // .text part1 | |
v62 = (int *)((char *)L2_FFF + (((unsigned int)&_dso_handle & 0xFF000) >> 10)); | |
if ( &_dso_handle < (int *)((char *)&loc_FFF1FFFC + 3) ) | |
{ | |
do | |
{ | |
v29 += 1024; | |
v63 = v29 != 0; | |
v64 = (HIWORD(v61) << 16) | 0x6615; | |
if ( v29 ) | |
v63 = (int *)((char *)&loc_FFF1FFFC + 3) > v29; | |
v61 += 4096; | |
*v62++ = v64; | |
} | |
while ( v63 ); | |
} | |
v65 = &g_dmaManagerLock; | |
v66 = &dword_FFF2E000; | |
v67 = 0x1FFED000u; | |
v68 = 0x1FFEC000u; | |
if ( ((unsigned int)&dword_FFF2E000 & 0xFFFF) != 0 ) | |
{ | |
v69 = (unsigned __int16)&dword_FFF2E000; | |
v70 = 0x1FFEC000 - v69; | |
v71 = 0x1FEA0000 + v69 - 536346625; | |
v72 = (int *)((char *)L2_FFF + (((unsigned int)&loc_FFF20000 & 0xFF000) >> 10)); | |
if ( v71 > (unsigned int)&loc_FFF20000 ) | |
{ | |
do | |
{ | |
v60 += 4096; | |
v73 = v60 != 0; | |
v74 = (v70 >> 12 << 12) | 0x796; // .text part2 | |
if ( v60 ) | |
v73 = v71 > (unsigned int)v60; | |
v70 += 4096; | |
*v72++ = v74; | |
} | |
while ( v73 ); | |
} | |
} | |
v75 = (int *)((char *)L2_FFF + (((unsigned int)&dword_FFF2E000 & 0xFF000) >> 10)); | |
if ( &dword_FFF2E000 < (int *)&unk_FFF2EFFF ) | |
{ | |
do | |
{ | |
v66 += 1024; | |
v76 = v66 != 0; | |
v77 = (v68 >> 12 << 12) | 0x797; // .rodata | |
if ( v66 ) | |
v76 = &unk_FFF2EFFF > (_UNKNOWN *)v66; | |
v68 += 4096; | |
*v75++ = v77; | |
} | |
while ( v76 ); | |
} | |
v78 = (int *)((char *)L2_FFF + (((unsigned int)&g_dmaManagerLock & 0xFF000) >> 10)); | |
if ( (unsigned int)&g_dmaManagerLock < 0xFFF33FFF ) | |
{ | |
do | |
{ | |
v65 += 512; | |
v79 = v67 >> 12 << 12; | |
v80 = v65 != 0; // .data and bss | |
if ( v65 ) | |
v80 = (unsigned int)v65 < 0xFFF33FFF; | |
v67 += 4096; | |
*v78++ = v79 | 0x597; | |
} | |
while ( v80 ); | |
} | |
L1Table = g_coreLocalRegions[0].L1Table; // core local regions etc | |
v82 = 0x1FFF8000; | |
v83 = L2_FFF + 0xCA; | |
do | |
{ | |
L1Table += 1024; | |
v84 = L1Table != 0; | |
v85 = (v82 >> 12 << 12) | 0x597; | |
if ( L1Table ) | |
v84 = (unsigned int)L1Table < 0xFFFCDFFF; | |
v82 += 4096; | |
*v83++ = v85; | |
} | |
while ( v84 ); | |
v86 = g_coreLocalRegions[1].L1Table; | |
v87 = L2_FFF + 211; | |
L2_FFF[0xCF] = 0x1FFF2597; | |
L2_FFF[0xD1] = 0x1FFF3597; | |
v88 = 0x1FFFC000; | |
do | |
{ | |
v86 += 1024; | |
v89 = v86 != 0; | |
v90 = v88 >> 12; | |
if ( v86 ) | |
v89 = (unsigned int)v86 < 0xFFFD6FFF; | |
v88 += 4096; | |
*v87++ = (v90 << 12) | 0x597; | |
} | |
while ( v89 ); | |
v91 = g_coreLocalRegions[2].L1Table; | |
L2_FFF[0xD8] = 0x1F3F2597; | |
L2_FFF[0xDA] = 0x1F3F5597; | |
v92 = 524255232; | |
v93 = L2_FFF + 0xDC; | |
do | |
{ | |
v91 += 1024; | |
v94 = v91 != 0; | |
v95 = (v92 >> 12 << 12) | 0x597; | |
if ( v91 ) | |
v94 = (unsigned int)v91 < 0xFFFDFFFF; | |
v92 += 4096; | |
*v93++ = v95; | |
} | |
while ( v94 ); | |
v96 = g_coreLocalRegions[3].L1Table; | |
v97 = L2_FFF + 0xE5; | |
L2_FFF[0xE1] = 0x1F3F3597; | |
L2_FFF[0xE3] = 0x1F3F6597; | |
v98 = 0x1F3FC000; | |
do | |
{ | |
v96 += 1024; | |
v99 = v96 != 0; | |
v100 = v98 >> 12; | |
if ( v96 ) | |
v99 = (unsigned int)v96 < 0xFFFE8FFF; | |
v98 += 4096; | |
*v97++ = (v100 << 12) | 0x597; | |
} | |
while ( v99 ); | |
L2_FFF[234] = 0x1F3F4597; | |
L2_FFF[236] = 0x1F3F7597; | |
v101 = (unsigned int)crt0::L1TableAddresses[coreId]; | |
v102 = crt0::idleThreadStacks[coreId]; | |
v103 = crt0::coreCtxAddrs[coreId]; | |
v104 = current.L1Table; | |
v105 = L2_FFF + 242; | |
do | |
{ | |
v104 += 1024; | |
v106 = v101 >> 12 << 12; | |
v107 = v104 != 0; | |
if ( v104 ) | |
v107 = (unsigned int)v104 < 0xFFFF5FFF; | |
v101 += 4096; | |
*v105++ = v106 | 0x597; | |
} | |
while ( v107 ); | |
L2_FFF[0xF7] = (v102 >> 12 << 12) | 0x597; | |
L2_FFF[0xF9] = (v103 >> 12 << 12) | 0x597; | |
L2_FFF[0xB8] = 0x17E10417; | |
v108 = &MPCORE; | |
v109 = L2_FFF + 0xEE; | |
L2_FFF[0xBA] = 0x10144417; // io | |
L2_FFF[0xBC] = 0x10400417; | |
L2_FFF[0xBE] = 0x10141417; | |
L2_FFF[0xC0] = 0x10163417; | |
L2_FFF[0xC2] = 0x10146417; | |
L2_FFF[0xC4] = 0x10202417; | |
L2_FFF[0xC6] = 0x10140417; | |
L2_FFF[0xC8] = 0x10206417; | |
v110 = &PA_MPCORE; | |
do | |
{ | |
v108 = (volatile Mp11PrivateMemRegion *)((char *)v108 + 4096); | |
v111 = v108 != 0; | |
if ( v108 ) | |
v111 = (unsigned int)v108 < 0xFFFEFFFF; | |
v112 = (unsigned int)v110 >> 12; | |
v110 = (volatile Mp11PrivateMemRegion *)((char *)v110 + 4096); | |
*v109++ = (v112 << 12) | 0x417; | |
} | |
while ( v111 ); | |
v113 = (char *)&KernStackL2Tables; | |
L2_FFF[0xF0] = 0x1FFF4796; // excep page | |
v114 = L2_FFF + 251; | |
do | |
{ | |
v113 += 4096; | |
v115 = v113 != 0; | |
v116 = (v5 >> 12 << 12) | 0x597; | |
if ( v113 ) | |
v115 = (unsigned int)v113 < 0xFFFFDFFF; // 0x1FFF5000, covering the 8 shared tables for 0xFF4.... (plus an extra page?) | |
v5 += 4096; | |
*v114++ = v116; | |
} | |
while ( v115 ); | |
} | |
// FFF2E000: using guessed type int dword_FFF2E000; | |
//----- (1FFAFC78) -------------------------------------------------------- | |
// write access to const memory has been detected, the output may be wrong! | |
void __fastcall crt0::InitCpu(s32 coreId) | |
{ | |
char socinfo; // r0 | |
unsigned int v3; // r0 | |
bool v4; // zf | |
char lgr_socmode; // r0 | |
int socModeHigherClk; // r10 | |
unsigned int v7; // r0 | |
u16 v8; // r0 | |
u8 v9; // r1 | |
u16 v10; // r0 | |
u16 v11; // r0 | |
int syncStatus; // r3 | |
u8 unitinfo; // r12 | |
u8 bootenv; // r0 | |
int i; // r0 | |
int v16; // r12 | |
char totalNumCores; // r1 | |
int prevSocModeBeforeLow; // r0 | |
unsigned int v19; // r1 | |
int socModeLowerClk; // r3 | |
u8 v21; // r12 | |
u16 v22; // r1 | |
u16 v23; // r1 | |
u8 lgr_brom_overlay_cnt; // r10 | |
u8 v25; // r10 | |
u8 v26; // r10 | |
u8 v27; // r10 | |
u8 v28; // r10 | |
int v29; // r10 | |
int v30; // r10 | |
u8 v31; // r0 | |
u16 v32; // r0 | |
u16 v33; // r0 | |
unsigned int v34; // r1 | |
u32 ctlr; // r1 | |
u32 reg1_aux_control; // r1 | |
u32 reg15_prefetch_ctrl; // r1 | |
u32 reg15_power_ctrl; // r1 | |
u32 reg2_int_clear; // r1 | |
int v40; // r0 | |
int v41; // r2 | |
int v42; // r1 | |
int v43; // t1 | |
if ( !coreId ) | |
{ | |
socinfo = PA_CONFIG11.socinfo; | |
if ( (unsigned __int8)(socinfo & 2) >> 1 ) | |
{ | |
v3 = PA_CONFIG11.socinfo & 4; | |
v4 = v3 >> 2 == 0; | |
lgr_socmode = PA_PDN.lgr_socmode; | |
if ( v4 ) | |
socModeHigherClk = 3; | |
else | |
socModeHigherClk = 5; | |
if ( (lgr_socmode & 7) != socModeHigherClk ) | |
{ | |
PA_PDN.lgr_cnt |= 1u; | |
v7 = PA_CONFIG11.socinfo & 4; | |
if ( v7 >> 2 ) | |
{ | |
v8 = PA_PDN.lgr_cnt | 0x100; // if LGR2 is supported, enable the L2C block | |
PA_PDN.lgr_cnt = v8; | |
} | |
crt0::WaitCycles(0x193u); // approx 1.5usec using the base Arm11 clk speed... | |
// except the caches aren't yet enabled, so | |
// SYSCLOCK_SOC (16MHz?) should be used as base instead | |
// (as the spin code triggers a strongly ordered | |
// AXIWRAM read at each instr. fetch) | |
PA_MPCORE.gicc.ctlr = 1; | |
PA_MPCORE.gicd.icpendr[2] = 0x1000000; | |
PA_PDN.lgr_socmode = socModeHigherClk & 7 | 0x8000; | |
PA_MPCORE.gicd.ipriorityr[KINTNAME_PDN] = 0; | |
v9 = PA_MPCORE.gicd.itargetsr[KINTNAME_PDN]; | |
PA_MPCORE.gicd.itargetsr[KINTNAME_PDN] = v9 | 1; | |
PA_MPCORE.gicd.isenabler[2] = 0x1000000; | |
do | |
{ | |
__wfi(); | |
v10 = PA_PDN.lgr_socmode; | |
} | |
while ( (v10 & 0x8000) == 0 ); | |
v11 = PA_PDN.lgr_socmode; | |
PA_PDN.lgr_socmode = v11; | |
PA_MPCORE.gicd.icenabler[2] = 0x1000000; | |
PA_CONFIG11.lgr_gpu_cnt = 3; // n3ds only reg, set bits 0 and 1 | |
} | |
PA_CONFIG11.lgr_cdma_sel = 0x3FFFF; | |
} // select new dma for everything | |
SYSRV.syncStatus = 1; | |
do | |
syncStatus = SYSRV.syncStatus; | |
while ( syncStatus != 2 ); | |
SYSRV.syncStatus = 3; | |
unitinfo = SYSRV.unitinfo; | |
crt0::unitinfo = unitinfo; | |
bootenv = SYSRV.bootenv; | |
crt0::bootenv = bootenv; | |
if ( crt0::unitinfo == 3 ) | |
{ | |
for ( i = 0; i < 0x800000; ++i ) | |
; | |
SYSRV.syncStatus = 1; | |
do | |
v16 = SYSRV.syncStatus; | |
while ( v16 != 2 ); | |
SYSRV.syncStatus = 3; | |
} | |
if ( (unsigned __int8)(PA_CONFIG11.socinfo & 2) >> 1 ) | |
{ | |
totalNumCores = PA_MPCORE.scu.cfgr; | |
if ( (totalNumCores & 3) == 3 ) | |
{ | |
PA_MPCORE.scu.statusr &= ~0xF0u; // Power off mode => Normal mode | |
prevSocModeBeforeLow = PA_PDN.lgr_socmode & 7; | |
v19 = PA_CONFIG11.socinfo & 4; | |
if ( v19 >> 2 ) | |
socModeLowerClk = 1; | |
else | |
socModeLowerClk = 2; | |
if ( prevSocModeBeforeLow != socModeLowerClk ) | |
{ | |
PA_MPCORE.gicc.ctlr = 1; | |
PA_MPCORE.gicd.icpendr[2] = 0x1000000; | |
PA_PDN.lgr_socmode = socModeLowerClk & 7 | 0x8000; | |
PA_MPCORE.gicd.ipriorityr[KINTNAME_PDN] = 0; | |
v21 = PA_MPCORE.gicd.itargetsr[88] | 1; | |
PA_MPCORE.gicd.itargetsr[KINTNAME_PDN] = v21; | |
PA_MPCORE.gicd.isenabler[2] = 0x1000000; | |
do | |
{ | |
__wfi(); | |
v22 = PA_PDN.lgr_socmode; | |
} | |
while ( (v22 & 0x8000) == 0 ); | |
v23 = PA_PDN.lgr_socmode; | |
PA_PDN.lgr_socmode = v23; | |
PA_MPCORE.gicd.icenabler[2] = 0x1000000; | |
} | |
lgr_brom_overlay_cnt = PA_CONFIG11.lgr_brom_overlay_cnt; | |
PA_CONFIG11.lgr_brom_overlay_cnt = lgr_brom_overlay_cnt | 1; | |
*(_DWORD *)((unsigned int)&PA_CONFIG11.lgr_brom_overlay_cnt | ((int)&PA_PDN >> 26)) = crt0::Core23Ep; | |
v25 = PA_PDN.lgr_cpu_cnt[2]; | |
if ( (v25 & 0x10) == 0 ) | |
{ | |
PA_PDN.lgr_cpu_cnt[2] |= 2u; | |
v26 = PA_PDN.lgr_cpu_cnt[2] | 1; | |
PA_PDN.lgr_cpu_cnt[2] = v26; | |
} | |
v27 = PA_PDN.lgr_cpu_cnt[3]; | |
if ( (v27 & 0x10) == 0 ) | |
{ | |
PA_PDN.lgr_cpu_cnt[3] |= 2u; | |
v28 = PA_PDN.lgr_cpu_cnt[3] | 1; | |
PA_PDN.lgr_cpu_cnt[3] = v28; | |
} | |
do | |
v29 = PA_PDN.lgr_cpu_cnt[2] & 0x12; | |
while ( v29 != 16 ); | |
do | |
v30 = PA_PDN.lgr_cpu_cnt[3] & 0x12; | |
while ( v30 != 16 ); | |
PA_CONFIG11.lgr_brom_overlay_cnt &= ~1u; | |
if ( prevSocModeBeforeLow != socModeLowerClk )// | |
// switch back to higher clock mode | |
// | |
// Could have just... not switched to higher-clock mode at first (early in the func)? | |
{ | |
PA_MPCORE.gicc.ctlr = 1; | |
PA_MPCORE.gicd.icpendr[2] = 0x1000000; | |
PA_PDN.lgr_socmode = prevSocModeBeforeLow & 7 | 0x8000; | |
PA_MPCORE.gicd.ipriorityr[88] = 0; | |
v31 = PA_MPCORE.gicd.itargetsr[88]; | |
PA_MPCORE.gicd.itargetsr[88] = v31 | 1; | |
PA_MPCORE.gicd.isenabler[2] = 0x1000000; | |
do | |
{ | |
__wfi(); | |
v32 = PA_PDN.lgr_socmode; | |
} | |
while ( (v32 & 0x8000) == 0 ); | |
v33 = PA_PDN.lgr_socmode; | |
PA_PDN.lgr_socmode = v33; | |
PA_MPCORE.gicd.icenabler[2] = 0x1000000; | |
} | |
} | |
} | |
SYSRV.core1Entrypoint = (u32)_start; | |
} | |
v34 = (unsigned int)crt0::L1TableAddresses[coreId]; | |
__mcr(15, 0, 0, 8, 7, 0); // TLB invalidate all | |
__mcr(15, 0, (v34 >> 9 << 9) | 0x12, 2, 0, 0); | |
__mcr(15, 0, (v34 >> 14 << 14) | 0x12, 2, 0, 1); | |
__mcr(15, 0, 2u, 2, 0, 2); | |
__mcr(15, 0, 0, 13, 0, 1); // CONTEXTIDR | |
__mcr(15, 0, 1u, 3, 0, 0); // DACR | |
crt0::PrepareTranslationTables(coreId); | |
if ( !coreId ) | |
{ | |
ctlr = PA_MPCORE.scu.ctlr; | |
PA_MPCORE.scu.ctlr = ctlr | 1; // enable SCU | |
} | |
__mcr(15, 0, __mrc(15, 0, 1, 0, 1) | 0x2F, 1, 0, 1);// Enables instruction folding, static branch prediction, dynamic branch prediction, and return stack. | |
// | |
// On top of what crt0 initalizes, also signal this CPU is taking part in SMP | |
__mcr(15, 0, __mrc(15, 0, 1, 0, 0) | 0xC03805, 1, 0, 0);// From LSB to MSB: Enable the MMU, L1 dcache, flow prediction, L1 icache, high vectors, unaligned access, extended page tables | |
__mcr(15, 0, 0, 7, 5, 4); // __isb(); | |
// | |
// __icache_inv_all(); | |
// __dcache_inv_all(); | |
// __tlb_inv_all(); | |
// | |
// __dsb(); | |
// __isb(); | |
__mcr(15, 0, 0, 7, 5, 0); | |
__mcr(15, 0, 0, 7, 6, 0); | |
__mcr(15, 0, 0, 8, 7, 0); | |
__mcr(15, 0, 0, 7, 10, 5); | |
__mcr(15, 0, 0, 7, 5, 4); | |
if ( !coreId ) | |
{ | |
reg1_aux_control = L2C.reg1_aux_control; | |
L2C.reg1_aux_control = reg1_aux_control & ~0x3901400u | 0x2800000;// Set: Force write allocate="force no allocate" | |
// Disable/unset: | |
// - High Priority for SO and Dev Reads | |
// - Exclusive cache configuration | |
// - Event monitor bus enable | |
// | |
// Enable RR | |
reg15_prefetch_ctrl = L2C.reg15_prefetch_ctrl; | |
L2C.reg15_prefetch_ctrl = reg15_prefetch_ctrl & ~0x79A0001Fu | 0x70000001;// Enable: | |
// - Double linefill | |
// - Instruction prefetch | |
// - Data prefetch | |
// - Double linefill on WRAP read (bit 27 unset) | |
// | |
// Disable: | |
// - Prefetch drop | |
// - Incr double Linefill | |
// - Not same ID on exclusive sequence | |
// | |
// Clear prefetch offset | |
reg15_power_ctrl = L2C.reg15_power_ctrl; | |
L2C.reg15_power_ctrl = reg15_power_ctrl & ~3u;// Disable dynamic clock gating and standby mode | |
reg2_int_clear = L2C.reg2_int_clear; | |
L2C.reg2_int_clear = reg2_int_clear | 0x1FF;// Clear all interrupts | |
L2C.reg7_inv_way = 0xFFFF; // Invalidate all | |
while ( (L2C.reg7_cache_sync & 1) != 0 ) | |
; | |
L2C.reg7_cache_sync = 0; | |
L2C.reg1_control |= 1u; // Enable L2C | |
v40 = 0x1FFF3FFC; | |
v41 = 0x1FFADFFC; | |
v42 = 0x200; // copy exception page from 1FFAE000 to 1FFF4000 | |
do | |
{ | |
--v42; | |
*(_DWORD *)(v40 + 4) = *(_DWORD *)(v41 + 4); | |
v43 = *(_DWORD *)(v41 + 8); | |
v41 += 8; | |
*(_DWORD *)(v40 + 8) = v43; | |
v40 += 8; | |
} | |
while ( v42 ); | |
if ( 0x1FFED000u << 20 ) | |
__breakpoint(89); | |
if ( 0x1FFEC000u << 20 ) | |
__breakpoint(90); | |
crt0::memmove((void *)0x1FFED000, (const void *)0x1FFB3000, 0x180u);// .data | |
crt0::memmove((void *)0x1FFEC000, (const void *)0x1FFB2000, 0x1000u);// .rodata | |
crt0::memmove( | |
(void *)(0x1FFEC000 - (unsigned __int16)&dword_FFF2E000),// remaining of .text | |
// first chunk of .text is at 0x1FF80000 | |
(const void *)0x1FFA0000, | |
(unsigned __int16)&dword_FFF2E000); | |
__mcr(15, 0, 0, 7, 10, 0); | |
__mcr(15, 0, 0, 7, 10, 4); | |
L2C.reg7_clean_inv_way = 0xFFFF; // bogus? No L1 clean and L2C doesn't hold dirty lines | |
while ( (L2C.reg7_cache_sync & 1) != 0 ) | |
; | |
L2C.reg7_cache_sync = 0; | |
} | |
__mcr(15, 0, 0, 7, 14, 0); // Clean and Invalidate Entire Data Cache | |
__mcr(15, 0, 0, 7, 10, 5); | |
__mcr(15, 0, 0, 7, 5, 0); // Invalidate entire instruction cache | |
__mcr(15, 0, 0, 7, 5, 6); | |
__mcr(15, 0, 0, 7, 10, 4); | |
__mcr(15, 0, 0, 7, 5, 4); | |
} | |
/* Orphan comments: | |
We NEED to switch to lower clock mode | |
before powering up cores 2 and 3. | |
wait for invalidation done | |
*/ | |
// 1FFAFD98: write access to const memory at 1FFB0415 has been detected | |
// 1FFAFDA0: write access to const memory at 1FFB0416 has been detected | |
// 1FFB0415: using guessed type char crt0::unitinfo; | |
// 1FFB0416: using guessed type char crt0::bootenv; | |
// FFF2E000: using guessed type int dword_FFF2E000; | |
//----- (1FFB02D4) -------------------------------------------------------- | |
u8 *crt0::FetchArm9Info(void) | |
{ | |
return (u8 *)&unk_1FFB0414; | |
} | |
//----- (1FFB02DC) -------------------------------------------------------- | |
void __fastcall crt0::memmove(void *dst, const void *src, u32 size) | |
{ | |
u32 v3; // r12 | |
int v4; // r3 | |
int v5; // t1 | |
char *v6; // r1 | |
char *v7; // r0 | |
int v8; // t1 | |
int j; // r2 | |
int v10; // t1 | |
char *v11; // r1 | |
char *v12; // r0 | |
int v13; // t1 | |
int v14; // t1 | |
int i; // r2 | |
int v16; // t1 | |
v3 = -3 - size + ((unsigned int)((int)(-3 - size) >> 31) >> 30); | |
v4 = (int)(-3 - size) / -4; | |
if ( src <= dst ) | |
{ | |
v11 = (char *)src + (size & 0xFFFFFFFC); | |
v12 = (char *)dst + (size & 0xFFFFFFFC); | |
if ( size <= 0x7FFFFFFF ) | |
{ | |
if ( v4 > 0 ) | |
{ | |
if ( (v3 & 4) != 0 ) | |
{ | |
v14 = *((_DWORD *)v11 - 1); | |
v11 -= 4; | |
*((_DWORD *)v12 - 1) = v14; | |
v12 -= 4; | |
} | |
for ( i = v4 >> 1; i; v12 -= 8 ) | |
{ | |
--i; | |
*((_DWORD *)v12 - 1) = *((_DWORD *)v11 - 1); | |
v16 = *((_DWORD *)v11 - 2); | |
v11 -= 8; | |
*((_DWORD *)v12 - 2) = v16; | |
} | |
} | |
} | |
else | |
{ | |
do | |
{ | |
v13 = *((_DWORD *)v11 - 1); | |
v11 -= 4; | |
size -= 4; | |
*((_DWORD *)v12 - 1) = v13; | |
v12 -= 4; | |
} | |
while ( size ); | |
} | |
} | |
else if ( size <= 0x7FFFFFFF ) | |
{ | |
if ( v4 > 0 ) | |
{ | |
v6 = (char *)src - 4; | |
v7 = (char *)dst - 4; | |
if ( (v3 & 4) != 0 ) | |
{ | |
v8 = *((_DWORD *)v6 + 1); | |
v6 += 4; | |
*((_DWORD *)v7 + 1) = v8; | |
v7 += 4; | |
} | |
for ( j = v4 >> 1; j; v7 += 8 ) | |
{ | |
--j; | |
*((_DWORD *)v7 + 1) = *((_DWORD *)v6 + 1); | |
v10 = *((_DWORD *)v6 + 2); | |
v6 += 8; | |
*((_DWORD *)v7 + 2) = v10; | |
} | |
} | |
} | |
else | |
{ | |
do | |
{ | |
v5 = *(_DWORD *)src; | |
src = (char *)src + 4; | |
size -= 4; | |
*(_DWORD *)dst = v5; | |
dst = (char *)dst + 4; | |
} | |
while ( size ); | |
} | |
} | |
//----- (1FFB0438) -------------------------------------------------------- | |
void _libc_init_array(void) | |
{ | |
void (*i)(void); // r4 | |
for ( i = (void (*)(void))&SHT__INIT_ARRAY__Base; | |
i != _sti___27_KCacheMaintenanceHelper_cpp; | |
i = (void (*)(void))((char *)i + 4) ) | |
{ | |
((void (*)(void))((char *)i + *(_DWORD *)i))(); | |
} | |
} | |
// 1FFB045C: using guessed type int (*SHT__INIT_ARRAY__Base)(); | |
//----- (1FFB04B0) -------------------------------------------------------- | |
void _sti___27_KCacheMaintenanceHelper_cpp(void) | |
{ | |
g_l2cLock.lockingThread = 0; | |
g_l2cLock.numWaiters = 0; | |
g_l2cLock.ticketCount = 0; | |
g_coreSynchronizationCount = 0; | |
g_cacheMaintenanceHelper.__vftable = &KCacheMaintenanceHelper::vt; | |
g_cacheMaintenanceHelper.op = KCACHEMAINTOP_NONE; | |
g_cacheMaintenanceHelper.numClients = 0; | |
g_cacheMaintenanceHelper.firstClientThread = 0; | |
g_cacheMaintenanceHelper.waitList.link.prev = 0; | |
g_cacheMaintenanceHelper.waitList.link.next = 0; | |
__aeabi_atexit_nopped( | |
(char *)_aeabi_vec_ctor_nocookie_nodtor_from_arm( | |
g_cacheMaintenanceHelper.tasks, | |
(void *(__fastcall *)(void *))KCacheMaintenanceHelperTask::KCacheMaintenanceHelperTask, | |
0xCu, | |
4u) | |
- 28, | |
(void (__fastcall *)(void *))KCacheMaintenanceHelper::~KCacheMaintenanceHelper, | |
&_dso_handle); | |
g_systemControlHelper.__vftable = &KSystemControlHelper::vt; | |
g_terminationHelper.__vftable = &KTerminationHelper::vt; | |
} | |
//----- (1FFB0558) -------------------------------------------------------- | |
void _sti___15_KDmaChannel_cpp(void) | |
{ | |
_aeabi_vec_ctor_nocookie_nodtor_from_arm( | |
g_dmaChannels, | |
(void *(__fastcall *)(void *))KDmaChannel::KDmaChannel, | |
0x528u, | |
8u); | |
_aeabi_atexit_veneer(0, (void (__fastcall *)(void *))DestroyDmaChannelInstances, &_dso_handle); | |
} | |
//----- (1FFB0594) -------------------------------------------------------- | |
void _sti___10_KDebug_cpp(void) | |
{ | |
g_debuggerThreadLinkedList.link.next = (KThreadLinkedListNode *)&g_debuggerThreadLinkedList.link; | |
g_debuggerThreadLinkedList.count = 0; | |
g_debuggerThreadLinkedList.link.prev = (KThreadLinkedListNode *)&g_debuggerThreadLinkedList.link; | |
_aeabi_atexit_veneer( | |
&g_debuggerThreadLinkedList, | |
(void (__fastcall *)(void *))KThreadLinkedList::~KThreadLinkedList, | |
&_dso_handle); | |
} | |
//----- (1FFB05C4) -------------------------------------------------------- | |
void _sti___10_KEvent_cpp(void) | |
{ | |
g_eventSignalMutex.lockingThread = 0; | |
g_eventSignalMutex.numWaiters = 0; | |
g_eventSignalMutex.ticketCount = 0; | |
} | |
//----- (1FFB05E0) -------------------------------------------------------- | |
void _sti___11_KTimer_cpp(void) | |
{ | |
g_timerOpsMutex.lockingThread = 0; | |
g_timerOpsMutex.numWaiters = 0; | |
g_timerOpsMutex.ticketCount = 0; | |
} | |
//----- (1FFB05FC) -------------------------------------------------------- | |
void _sti___10_Kernel_cpp(void) | |
{ | |
KDmaManager *__shifted(KDmaManager,0xC) v0; // r0 | |
g_supervisorPageTable.mutex.lockingThread = 0; | |
g_supervisorPageTable.mutex.numWaiters = 0; | |
g_supervisorPageTable.mutex.ticketCount = 0; | |
g_supervisorPageTable.memoryBlockMgr.blocks.link.next = (KMemoryBlockLinkedListNode *)&g_supervisorPageTable.memoryBlockMgr.blocks.link; | |
g_supervisorPageTable.memoryBlockMgr.blocks.count = 0; | |
g_supervisorPageTable.memoryBlockMgr.blocks.link.prev = (KMemoryBlockLinkedListNode *)&g_supervisorPageTable.memoryBlockMgr.blocks.link; | |
__aeabi_atexit_nopped( | |
&g_supervisorPageTable, | |
(void (__fastcall *)(void *))KSupervisorPageTable::~KSupervisorPageTable, | |
&_dso_handle); | |
g_memoryManager.pgMgr.memoryStartAddr = 0; | |
g_memoryManager.pgMgr.numPages = 0; | |
g_memoryManager.pgMgr.pageRefcounts = 0; | |
g_memoryManager.pgMgr.kernelMemoryUsage = 0; | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
g_memoryManager.pgMgr.mutex.numWaiters = 0; | |
g_memoryManager.pgMgr.mutex.ticketCount = 0; | |
g_interruptManager.mutex.lockingThread = 0; | |
g_interruptManager.mutex.numWaiters = 0; | |
g_interruptManager.mutex.ticketCount = 0; | |
__aeabi_atexit_nopped( | |
&g_interruptManager, | |
(void (__fastcall *)(void *))KInterruptManager::~KInterruptManager, | |
&_dso_handle); | |
g_hardwareTimer.__vftable = &KHardwareTimer::vt; | |
g_hardwareTimer.next = 0; | |
g_hardwareTimer.innerTask.__vftable = &KDummyTimerTask::vt; | |
g_hardwareTimer.innerTask.next = 0; | |
g_hardwareTimer.lock.lockingThread = 0; | |
g_hardwareTimer.lock.lockCount = 0; | |
g_dmaManager.vt = &KDmaManager::vt_KDmaChannelEventHandler; | |
g_dmaManager.__vftable = &KDmaManager::vt; | |
g_dmaManager.next = 0; | |
v0 = (KDmaManager *__shifted(KDmaManager,0xC))_aeabi_vec_ctor_nocookie_nodtor_from_arm( | |
g_dmaManager.channelLocked, | |
(void *(__fastcall *)(void *))AtomicBool::AtomicBool, | |
1u, | |
8u); | |
_aeabi_vec_ctor_nocookie_nodtor_from_arm( | |
ADJ(v0)->interruptTaskEnqueued, | |
(void *(__fastcall *)(void *))AtomicBool::AtomicBool, | |
1u, | |
8u); | |
g_perfCounterMgr.__vftable = &KPerformanceCounterManager::vt; | |
__aeabi_atexit_nopped( | |
&g_perfCounterMgr, | |
(void (__fastcall *)(void *))KPerformanceCounterManager::~KPerformanceCounterManager, | |
&_dso_handle); | |
unk_FFF2F0E0 = 0LL; | |
unk_FFF2F0E8 = 0LL; | |
} | |
//----- (1FFB0768) -------------------------------------------------------- | |
void _sti___11_KThread_cpp(void) | |
{ | |
g_threadIdCounter = 0; | |
} | |
//----- (1FFB077C) -------------------------------------------------------- | |
void _sti___26_KVfpRegisterDumpHelper_cpp(void) | |
{ | |
_aeabi_vec_ctor_nocookie_nodtor_from_arm( | |
&g_vfpRegisterDumpHelper, | |
(void *(__fastcall *)(void *))KVfpRegisterDumpHelperImpl::KVfpRegisterDumpHelperImpl, | |
8u, | |
4u); | |
} | |
//----- (1FFB0798) -------------------------------------------------------- | |
void _sti___12_KProcess_cpp(void) | |
{ | |
g_pidCounter = 0; | |
} | |
//----- (1FFB07AC) -------------------------------------------------------- | |
void _sti___21_KProcessPageTable_cpp(void) | |
{ | |
_aeabi_vec_ctor_nocookie_nodtor_from_arm( | |
g_tlbMaintenanceHelper.impls, | |
(void *(__fastcall *)(void *))KTlbMaintenanceHelperImpl::KTlbMaintenanceHelperImpl, | |
0x10u, | |
4u); | |
g_asidManager.mutex.lockingThread = 0; | |
g_asidManager.mutex.numWaiters = 0; | |
g_asidManager.mutex.ticketCount = 0; | |
g_asidManager.map[1] = 0; | |
g_asidManager.map[2] = 0; | |
g_asidManager.map[3] = 0; | |
g_asidManager.map[4] = 0; | |
g_asidManager.map[5] = 0; | |
g_asidManager.map[6] = 0; | |
g_asidManager.map[7] = 0; | |
g_asidManager.index = 0; | |
g_asidManager.map[0] = 1; | |
g_level2TtblAllocator.rootNode = 0; | |
g_level2TtblAllocator.mutex.lockingThread = 0; | |
g_level2TtblAllocator.mutex.numWaiters = 0; | |
g_level2TtblAllocator.mutex.ticketCount = 0; | |
_aeabi_atexit_veneer( | |
&g_level2TtblAllocator, | |
(void (__fastcall *)(void *))KLevel2TranslationTableAllocator::~KLevel2TranslationTableAllocator, | |
&_dso_handle); | |
} | |
//----- (1FFB083C) -------------------------------------------------------- | |
void _sti___14_KScheduler_cpp(void) | |
{ | |
g_cpuTimeLimiterMode0.next = 0; | |
g_cpuTimeLimiterMode0.__vftable = &KCpuTimeLimiterMode0::vt; | |
g_cpuTimeLimiterMode1.next = 0; | |
g_cpuTimeLimiterMode1.__vftable = &KCpuTimeLimiterMode1::vt; | |
g_schedulerLock.lockingThread = 0; | |
g_schedulerLock.lockCount = 0; | |
g_schedulerPreemptedThreadList.link.prev = 0; | |
g_schedulerPreemptedThreadList.link.next = 0; | |
} | |
//----- (1FFB088C) -------------------------------------------------------- | |
void _sti___15_KLinkedList_cpp(void) | |
{ | |
g_linkedListNodeSlabHeap.currentHead = 0; | |
g_linkedListNodeSlabHeap.totalSize = 0; | |
_aeabi_atexit_veneer(&g_linkedListNodeSlabHeap, (void (__fastcall *)(void *))KSlabHeap::~KSlabHeap, &_dso_handle); | |
} | |
//----- (1FFB08B4) -------------------------------------------------------- | |
void _sti___15_KObjectName_cpp(void) | |
{ | |
g_objectNameList.link.next = (KObjectNameLinkedListNode *)&g_objectNameList.link; | |
g_objectNameList.count = 0; | |
g_objectNameList.link.prev = (KObjectNameLinkedListNode *)&g_objectNameList.link; | |
__cxa_atexit_nopped((void (__fastcall *)(void *))&g_objectNameList, KLinkedList::~KLinkedList, &_dso_handle); | |
g_objectNameListMutex.lockingThread = 0; | |
g_objectNameListMutex.numWaiters = 0; | |
g_objectNameListMutex.ticketCount = 0; | |
} | |
//----- (1FFB0900) -------------------------------------------------------- | |
void _sti___31_KPerformanceCounterManager_cpp(void) | |
{ | |
g_perfCounterMgrExclusivePid = -1; | |
} | |
//----- (1FFB0914) -------------------------------------------------------- | |
void _sti___9_Sleep_cpp(void) | |
{ | |
g_systemControl.mutex.lockingThread = 0; | |
g_systemControl.mutex.numWaiters = 0; | |
g_systemControl.mutex.ticketCount = 0; | |
_aeabi_vec_ctor_nocookie_nodtor_from_arm( | |
&g_sleepEntrySchedHelper, | |
(void *(__fastcall *)(void *))KSleepEntrySchedHelperImpl::KSleepEntrySchedHelperImpl, | |
8u, | |
4u); | |
_aeabi_vec_ctor_nocookie_nodtor_from_arm( | |
&g_sleepExitSchedHelper, | |
(void *(__fastcall *)(void *))KSleepExitSchedHelperImpl::KSleepExitSchedHelperImpl, | |
8u, | |
4u); | |
} | |
//----- (1FFB096C) -------------------------------------------------------- | |
void _sti___15_KDmaManager_cpp(void) | |
{ | |
g_dmaManagerLock.lockingThread = 0; | |
g_dmaManagerLock.numWaiters = 0; | |
g_dmaManagerLock.ticketCount = 0; | |
} | |
//----- (1FFB0988) -------------------------------------------------------- | |
void _sti___27_KObjectAllocatorAdapter_cpp(void) | |
{ | |
if ( (`guard variable for'KSlabHeap<KDebug>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KDebug>::KSlabHeap(void)::initialized )// nopped __cxa_guard_acquire and atexit calls in each block | |
// but I CBA to add them | |
{ | |
g_debugAllocator.slabHeap.currentHead = 0; | |
g_debugAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KDebug>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KDebug>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_debugAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KThread>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KThread>::KSlabHeap(void)::initialized ) | |
{ | |
g_threadAllocator.slabHeap.currentHead = 0; | |
g_threadAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KThread>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KThread>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_threadAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KAddressArbiter>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KAddressArbiter>::KSlabHeap(void)::initialized ) | |
{ | |
g_addressArbiterAllocator.slabHeap.currentHead = 0; | |
g_addressArbiterAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KAddressArbiter>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KAddressArbiter>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_addressArbiterAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KCodeSet>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KCodeSet>::KSlabHeap(void)::initialized ) | |
{ | |
g_codeSetAllocator.slabHeap.currentHead = 0; | |
g_codeSetAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KCodeSet>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KCodeSet>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_codeSetAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KDmaObject>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KDmaObject>::KSlabHeap(void)::initialized ) | |
{ | |
g_dmaObjectAllocator.slabHeap.currentHead = 0; | |
g_dmaObjectAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KDmaObject>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KDmaObject>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_dmaObjectAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KEvent>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KEvent>::KSlabHeap(void)::initialized ) | |
{ | |
g_eventAllocator.slabHeap.currentHead = 0; | |
g_eventAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KEvent>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KEvent>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_eventAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KMutex>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KMutex>::KSlabHeap(void)::initialized ) | |
{ | |
g_mutexAllocator.slabHeap.currentHead = 0; | |
g_mutexAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KMutex>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KMutex>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_mutexAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KPort>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KPort>::KSlabHeap(void)::initialized ) | |
{ | |
g_portAllocator.slabHeap.currentHead = 0; | |
g_portAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KPort>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KPort>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_portAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KResourceLimit>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KResourceLimit>::KSlabHeap(void)::initialized ) | |
{ | |
g_resourceLimitAllocator.slabHeap.currentHead = 0; | |
g_resourceLimitAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KResourceLimit>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KResourceLimit>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_resourceLimitAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KProcess>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KProcess>::KSlabHeap(void)::initialized ) | |
{ | |
g_processAllocator.slabHeap.currentHead = 0; | |
g_processAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KProcess>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KProcess>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_processAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KSemaphore>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KSemaphore>::KSlabHeap(void)::initialized ) | |
{ | |
g_semaphoreAllocator.slabHeap.currentHead = 0; | |
g_semaphoreAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KSemaphore>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KSemaphore>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_semaphoreAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KSession>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KSession>::KSlabHeap(void)::initialized ) | |
{ | |
g_sessionAllocator.slabHeap.currentHead = 0; | |
g_sessionAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KSession>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KSession>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_sessionAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KSharedMemory>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KSharedMemory>::KSlabHeap(void)::initialized ) | |
{ | |
g_sharedMemoryAllocator.slabHeap.currentHead = 0; | |
g_sharedMemoryAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KSharedMemory>::KObjectContainer(void)::initialized & 1) == 0 | |
&& &`guard variable for'KObjectContainer<KSharedMemory>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_sharedMemoryAllocator.container); | |
} | |
if ( (`guard variable for'KSlabHeap<KTimer>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KTimer>::KSlabHeap(void)::initialized ) | |
{ | |
g_timerAllocator.slabHeap.currentHead = 0; | |
g_timerAllocator.slabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KObjectContainer<KTimer>::KObjectContainer(void)::initialized & 1) == 0 ) | |
{ | |
if ( &`guard variable for'KObjectContainer<KTimer>::KObjectContainer(void)::initialized ) | |
{ | |
KObjectContainer::KObjectContainer(&g_timerAllocator.container); | |
_cxa_guard_release_veneer(&`guard variable for'KObjectContainer<KTimer>::KObjectContainer(void)::initialized); | |
} | |
} | |
} | |
// FFF2F0F8: using guessed type int `guard variable for'KObjectContainer<KDmaObject>::KObjectContainer(void)::initialized; | |
// FFF2F0FC: using guessed type int `guard variable for'KSlabHeap<KDmaObject>::KSlabHeap(void)::initialized; | |
// FFF2F100: using guessed type int `guard variable for'KObjectContainer<KSemaphore>::KObjectContainer(void)::initialized; | |
// FFF2F104: using guessed type int `guard variable for'KSlabHeap<KSemaphore>::KSlabHeap(void)::initialized; | |
// FFF2F108: using guessed type int `guard variable for'KObjectContainer<KSharedMemory>::KObjectContainer(void)::initialized; | |
// FFF2F10C: using guessed type int `guard variable for'KSlabHeap<KSharedMemory>::KSlabHeap(void)::initialized; | |
// FFF2F110: using guessed type int `guard variable for'KObjectContainer<KResourceLimit>::KObjectContainer(void)::initialized; | |
// FFF2F114: using guessed type int `guard variable for'KSlabHeap<KResourceLimit>::KSlabHeap(void)::initialized; | |
// FFF2F118: using guessed type int `guard variable for'KObjectContainer<KAddressArbiter>::KObjectContainer(void)::initialized; | |
// FFF2F11C: using guessed type int `guard variable for'KSlabHeap<KAddressArbiter>::KSlabHeap(void)::initialized; | |
// FFF2F120: using guessed type int `guard variable for'KObjectContainer<KPort>::KObjectContainer(void)::initialized; | |
// FFF2F124: using guessed type int `guard variable for'KSlabHeap<KPort>::KSlabHeap(void)::initialized; | |
// FFF2F128: using guessed type int `guard variable for'KObjectContainer<KEvent>::KObjectContainer(void)::initialized; | |
// FFF2F12C: using guessed type int `guard variable for'KSlabHeap<KEvent>::KSlabHeap(void)::initialized; | |
// FFF2F130: using guessed type int `guard variable for'KObjectContainer<KMutex>::KObjectContainer(void)::initialized; | |
// FFF2F134: using guessed type int `guard variable for'KSlabHeap<KMutex>::KSlabHeap(void)::initialized; | |
// FFF2F13C: using guessed type int `guard variable for'KSlabHeap<KTimer>::KSlabHeap(void)::initialized; | |
// FFF2F140: using guessed type int `guard variable for'KObjectContainer<KDebug>::KObjectContainer(void)::initialized; | |
// FFF2F144: using guessed type int `guard variable for'KSlabHeap<KDebug>::KSlabHeap(void)::initialized; | |
// FFF2F148: using guessed type int `guard variable for'KObjectContainer<KThread>::KObjectContainer(void)::initialized; | |
// FFF2F14C: using guessed type int `guard variable for'KSlabHeap<KThread>::KSlabHeap(void)::initialized; | |
// FFF2F150: using guessed type int `guard variable for'KObjectContainer<KCodeSet>::KObjectContainer(void)::initialized; | |
// FFF2F154: using guessed type int `guard variable for'KSlabHeap<KCodeSet>::KSlabHeap(void)::initialized; | |
// FFF2F158: using guessed type int `guard variable for'KObjectContainer<KProcess>::KObjectContainer(void)::initialized; | |
// FFF2F15C: using guessed type int `guard variable for'KSlabHeap<KProcess>::KSlabHeap(void)::initialized; | |
// FFF2F160: using guessed type int `guard variable for'KObjectContainer<KSession>::KObjectContainer(void)::initialized; | |
// FFF2F164: using guessed type int `guard variable for'KSlabHeap<KSession>::KSlabHeap(void)::initialized; | |
//----- (1FFB1274) -------------------------------------------------------- | |
void _sti___21_KPxiBufferManager_cpp(void) | |
{ | |
int v0; // r2 | |
int v1; // r1 | |
int v2; // r12 | |
int v3; // r2 | |
int v4; // r4 | |
g_pxiBufferManager.mutex.lockingThread = 0; | |
g_pxiBufferManager.mutex.numWaiters = 0; | |
v0 = 0; | |
g_pxiBufferManager.mutex.ticketCount = 0; | |
v1 = 0; | |
do | |
{ | |
v2 = v0; | |
v3 = v0 + 1; | |
v1 += 2; | |
v4 = v3; | |
g_pxiBufferManager.ctxs[v2].clientThread = 0; | |
v0 = v3 + 1; | |
g_pxiBufferManager.ctxs[v4].clientThread = 0; | |
} | |
while ( v1 < 64 ); | |
} | |
//----- (1FFB12D8) -------------------------------------------------------- | |
void _sti___14_KFiqHelper_cpp(void) | |
{ | |
g_fiqHelper.s.next = 0; | |
g_fiqHelper.s.__vftable = &KFiqHelper::vt; | |
g_fiqHelper.interruptEvent = 0; | |
g_fiqState = KFIQSTATE_UNBOUND; | |
} | |
//----- (1FFB1308) -------------------------------------------------------- | |
void _sti___20_KSlabHeapAdapter_cpp(void) | |
{ | |
if ( (`guard variable for'KSlabHeap<KEventInfo>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KEventInfo>::KSlabHeap(void)::initialized )// nopped __cxa_guard_acquire and atexit calls in each block | |
// but I CBA to add them | |
{ | |
g_eventInfoSlabHeap.currentHead = 0; | |
g_eventInfoSlabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KSlabHeap<KMemoryBlock>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KMemoryBlock>::KSlabHeap(void)::initialized ) | |
{ | |
g_memoryBlockSlabHeap.currentHead = 0; | |
g_memoryBlockSlabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KSlabHeap<KObjectName>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KObjectName>::KSlabHeap(void)::initialized ) | |
{ | |
g_objectNameSlabHeap.currentHead = 0; | |
g_objectNameSlabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KSlabHeap<KBlockInfo>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KBlockInfo>::KSlabHeap(void)::initialized ) | |
{ | |
g_blockInfoSlabHeap.currentHead = 0; | |
g_blockInfoSlabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KSlabHeap<KDebugThread>::KSlabHeap(void)::initialized & 1) == 0 | |
&& &`guard variable for'KSlabHeap<KDebugThread>::KSlabHeap(void)::initialized ) | |
{ | |
g_debugThreadSlabHeap.currentHead = 0; | |
g_debugThreadSlabHeap.totalSize = 0; | |
} | |
if ( (`guard variable for'KSlabHeap<KThreadLocalPage>::KSlabHeap(void)::initialized & 1) == 0 ) | |
{ | |
if ( &`guard variable for'KSlabHeap<KThreadLocalPage>::KSlabHeap(void)::initialized ) | |
{ | |
g_threadLocalPageSlabHeap.currentHead = 0; | |
g_threadLocalPageSlabHeap.totalSize = 0; | |
_cxa_guard_release_veneer(&`guard variable for'KSlabHeap<KThreadLocalPage>::KSlabHeap(void)::initialized); | |
} | |
} | |
} | |
// FFF2F168: using guessed type int `guard variable for'KSlabHeap<KBlockInfo>::KSlabHeap(void)::initialized; | |
// FFF2F16C: using guessed type int `guard variable for'KSlabHeap<KEventInfo>::KSlabHeap(void)::initialized; | |
// FFF2F170: using guessed type int `guard variable for'KSlabHeap<KObjectName>::KSlabHeap(void)::initialized; | |
// FFF2F174: using guessed type int `guard variable for'KSlabHeap<KMemoryBlock>::KSlabHeap(void)::initialized; | |
// FFF2F17C: using guessed type int `guard variable for'KSlabHeap<KDebugThread>::KSlabHeap(void)::initialized; | |
//----- (1FFB1508) -------------------------------------------------------- | |
void _sti___29_KPerformanceControlHelper_cpp(void) | |
{ | |
g_perfCounterControlHelper.__vftable = &KPerformanceCounterControlHelper::vt; | |
} | |
//----- (1FFF4994) -------------------------------------------------------- | |
void crt0::CopyAndJumpToCore0Stub(void) | |
{ | |
crt0::CopyFinalStub(crt0::Core0StubData, crt0::CopyAndJumpToCore1Stub, crt0::Core0Stub); | |
crt0::Core0Stub(); | |
} | |
//----- (1FFF49AC) -------------------------------------------------------- | |
void __usercall __noreturn crt0::Core0StubData() | |
{ | |
void (**v0)(void); // r0 | |
v0 = (void (**)(void))off_1FFF49D8; | |
*(_DWORD *)off_1FFF49D8 = 0; | |
*(_DWORD *)off_1FFF49DC = dword_1FFF49E0; | |
while ( !*v0 ) | |
; | |
(*v0)(); | |
} | |
// 1FFF49D8: using guessed type void *off_1FFF49D8; | |
// 1FFF49DC: using guessed type void *off_1FFF49DC; | |
// 1FFF49E0: using guessed type int dword_1FFF49E0; | |
//----- (1FFF49E4) -------------------------------------------------------- | |
void __noreturn crt0::CopyAndJumpToCore1Stub(void) | |
{ | |
crt0::CopyFinalStub(crt0::Core1StubData, crt0::CopyFinalStub, crt0::Core1FinalStub); | |
crt0::Core1FinalStub(__mrc(15, 0, 0, 0, 5)); | |
} | |
//----- (1FFF4A00) -------------------------------------------------------- | |
void __usercall __noreturn crt0::Core1StubData(s32 coreId@<R2>) | |
{ | |
_DWORD *v1; // r3 | |
void (**v2)(void); // lr | |
*(_DWORD *)off_1FFF4A64 = 1; | |
*(_DWORD *)off_1FFF4A68 = 1; | |
v1 = off_1FFF4A6C; | |
*(_DWORD *)off_1FFF4A6C = -1; | |
v2 = (void (**)(void))off_1FFF4A70; | |
*off_1FFF4A74 = 1; | |
do | |
__wfi(); | |
while ( (*v1 & (1 << coreId)) == 0 ); | |
(*v2)(); | |
} | |
// 1FFF4A64: using guessed type void *off_1FFF4A64; | |
// 1FFF4A68: using guessed type void *off_1FFF4A68; | |
// 1FFF4A6C: using guessed type void *off_1FFF4A6C; | |
// 1FFF4A70: using guessed type void *off_1FFF4A70; | |
// 1FFF4A74: using guessed type char *off_1FFF4A74; | |
//----- (1FFF4A78) -------------------------------------------------------- | |
void __fastcall crt0::CopyFinalStub(const void *start, const void *end, void *dst) | |
{ | |
int v3; // r3 | |
char *v4; // r0 | |
char *v5; // r1 | |
int v6; // t1 | |
int i; // r2 | |
int v8; // t1 | |
v3 = (_BYTE *)end - (_BYTE *)start; | |
if ( ((_BYTE *)end - (_BYTE *)start) >> 2 > 0 ) | |
{ | |
v4 = (char *)start - 4; | |
v5 = (char *)dst - 4; | |
if ( (v3 & 4) != 0 ) | |
{ | |
v6 = *((_DWORD *)v4 + 1); | |
v4 += 4; | |
*(_DWORD *)dst = v6; | |
v5 = (char *)dst; | |
} | |
for ( i = v3 >> 3; i; v5 += 8 ) | |
{ | |
--i; | |
*((_DWORD *)v5 + 1) = *((_DWORD *)v4 + 1); | |
v8 = *((_DWORD *)v4 + 2); | |
v4 += 8; | |
*((_DWORD *)v5 + 2) = v8; | |
} | |
} | |
} | |
//----- (1FFF4AC4) -------------------------------------------------------- | |
void __fastcall crt0::StopExtraCoresAndJump(s32 coreId) | |
{ | |
u32 v5; // r0 | |
char lgr_socmode; // r12 | |
u8 v7; // r12 | |
u8 v8; // r12 | |
u8 v9; // r5 | |
u16 v10; // r4 | |
u16 v11; // r1 | |
unsigned int v12; // r4 | |
u32 v13; // r4 | |
u8 v14; // r0 | |
u32 iar; // r0 | |
__mcr(15, 0, 0, 7, 14, 0); // cleaninv entire dcache (local) | |
__mcr(15, 0, 0, 7, 10, 5); | |
__mcr(15, 0, 0xFu, 1, 0, 1); // aux control | |
__mcr(15, 0, 0x54078u, 1, 0, 0); // control | |
__mcr(15, 0, 0, 2, 0, 0); // disable mmu, write 0 to the translation registers | |
__mcr(15, 0, 0, 2, 0, 1); | |
__mcr(15, 0, 0, 2, 0, 2); | |
__mcr(15, 0, 0, 13, 0, 1); | |
__mcr(15, 0, 0, 7, 5, 4); // flush prefetch buffer | |
__asm { CPSID IF } | |
if ( coreId ) | |
{ | |
switch ( coreId ) | |
{ | |
case 1: | |
crt0::CopyAndJumpToCore1Stub(); | |
case 2: | |
v5 = PA_MPCORE.scu.statusr | 0x30; // set SCU status to indicate the core is about to enter Power Off mode (core 2) | |
break; | |
case 3: | |
do | |
v14 = PA_PDN.lgr_cpu_cnt[2]; // wait for core 2 to be off | |
while ( (v14 & 0x10) != 0 ); | |
v5 = PA_MPCORE.scu.statusr | 0xC0; // set SCU status to indicate the core is about to enter Power Off mode (core 3) | |
break; | |
default: | |
goto LABEL_27; | |
} | |
PA_MPCORE.scu.statusr = v5; | |
while ( 1 ) | |
{ | |
LABEL_27: | |
__wfi(); // core 2 and 3: basically, wfi forever | |
iar = PA_MPCORE.gicc.iar; | |
PA_MPCORE.gicc.eoir = iar; | |
} | |
} | |
lgr_socmode = PA_PDN.lgr_socmode; // core 0 | |
if ( (lgr_socmode & 7) != 0 ) | |
{ | |
if ( (PA_MPCORE.scu.cfgr & 3) == 3 ) | |
{ | |
PA_PDN.lgr_cpu_cnt[2] = 0; // set Power Off for core 2. Only takes effect when SCU status becomes "Power off" | |
do | |
v7 = PA_PDN.lgr_cpu_cnt[2]; | |
while ( (v7 & 0x10) != 0 ); | |
PA_PDN.lgr_cpu_cnt[3] = 0; | |
do | |
v8 = PA_PDN.lgr_cpu_cnt[3]; // same for core 3 | |
while ( (v8 & 0x10) != 0 ); | |
} | |
PA_CONFIG11.lgr_gpu_cnt = 0; // set SoC mode to CTR | |
PA_PDN.lgr_cnt = 0; | |
PA_MPCORE.gicc.ctlr = 1; | |
PA_MPCORE.gicd.icpendr[2] = 0x1000000; | |
PA_PDN.lgr_socmode = 0x8000; | |
PA_MPCORE.gicd.ipriorityr[KINTNAME_PDN] = 0; | |
v9 = PA_MPCORE.gicd.itargetsr[KINTNAME_PDN]; | |
PA_MPCORE.gicd.itargetsr[KINTNAME_PDN] = v9 | 1; | |
PA_MPCORE.gicd.isenabler[2] = 0x1000000; | |
while ( 1 ) | |
{ | |
__wfi(); | |
v10 = PA_PDN.lgr_socmode; | |
if ( (v10 & 0x8000) != 0 ) | |
break; | |
v12 = PA_MPCORE.gicc.hppir & 0x3FF; | |
if ( v12 <= 0x15 ) // bug, this is meant to be 15 (decimal) | |
// | |
// throw away all SGIs | |
{ | |
v13 = PA_MPCORE.gicc.iar; | |
PA_MPCORE.gicc.eoir = v13; | |
} | |
} | |
v11 = PA_PDN.lgr_socmode; | |
PA_PDN.lgr_socmode = v11; | |
PA_MPCORE.gicd.icenabler[2] = 0x1000000; | |
} | |
PA_CONFIG11.lgr_cdma_sel = 0; // make all devices use O3DS dma again | |
while ( !crt0::core1ReadyForFirmlaunch ) // wait fore core1 to be ready | |
; | |
crt0::CopyAndJumpToCore0Stub(); | |
} | |
//----- (1FFFFC00) -------------------------------------------------------- | |
void __usercall __noreturn crt0::Core0Stub() | |
{ | |
SYSRV.core0Entrypoint = 0; | |
PA_PXI.send = 0x44846; | |
while ( !SYSRV.core0Entrypoint ) | |
; | |
((void (__noreturn *)(void))SYSRV.core0Entrypoint)(); | |
} | |
//----- (1FFFFE00) -------------------------------------------------------- | |
void __usercall __noreturn crt0::Core1FinalStub(s32 coreId@<R2>) | |
{ | |
void (*core1Entrypoint)(void); // lr | |
PA_MPCORE.gicc.ctlr = 1; | |
PA_MPCORE.gicd.ctlr = 1; | |
PA_MPCORE.gicd.icpendr[0] = -1; | |
crt0::core1ReadyForFirmlaunch = 1; | |
do | |
__wfi(); | |
while ( (PA_MPCORE.gicd.icpendr[0] & (1 << coreId)) == 0 ); | |
core1Entrypoint = (void (*)(void))SYSRV.core1Entrypoint; | |
core1Entrypoint(); | |
} | |
//----- (FFF0000C) -------------------------------------------------------- | |
int __fastcall _aeabi_vec_dtor(int a1, void (__fastcall *a2)(int), int a3, int a4) | |
{ | |
int v7; // r4 | |
if ( a4 ) | |
{ | |
v7 = a3 * a4 + a1; | |
do | |
{ | |
v7 -= a3; | |
a2(v7); | |
} | |
while ( a1 != v7 ); | |
} | |
return a1 - 8; | |
} | |
//----- (FFF00030) -------------------------------------------------------- | |
void __noreturn HorizonKernelMain(void) | |
{ | |
s32 coreId; // r5 | |
KCoreLocalContext *p_clc; // r8 | |
int v2; // r0 | |
char *heap; // r4 | |
FcramLayout stackTop; // [sp+0h] [bp-18h] BYREF | |
coreId = __mrc(15, 0, 0, 0, 5) & 3; | |
KCoreLocalContext::InitializeCurrent(coreId); | |
g_kernelState = KSTATE_INITIALIZING; | |
p_clc = &g_coreLocalRegions[coreId].clc; | |
KAutoObject::Initialize(&p_clc->idleThread); | |
KThread::Initialize(&p_clc->idleThread, 0, 0, 0xFFFF8000, 0, 1, coreId, 0, KTHREAD_TYPE_IDLE);// KTHREAD_TYPE_IDLE. | |
// It's initialized as the first thread with prio 0, meaning it won't be scheduled out until | |
// its priority is set to 64. | |
current.clc.current.thread = &p_clc->idleThread; | |
current.clc.current.process = 0; | |
KInterruptManager::InitializeCore(&g_interruptManager, coreId); | |
KHardwareTimer::Initialize(&g_hardwareTimer, coreId); | |
KScheduler::Intialize(current.clc.current.scheduler, coreId, &p_clc->idleThread); | |
cpu::SynchronizeAllCores(); | |
if ( !coreId ) | |
{ | |
ParseDeliverArgs(&stackTop); | |
KMemoryManager::Intialize(&g_memoryManager, &stackTop, 0xE0000000, 0x10000000u); | |
} | |
cpu::SynchronizeAllCores(); | |
KLevel2TranslationTableAllocator::Initialize(coreId); | |
if ( coreId ) | |
{ | |
if ( coreId == 1 ) | |
{ | |
AllocateSharedConfigPages(); | |
KDebug::InitializeScheduledInOutState(); | |
KDmaManager::Initialize(&g_dmaManager); | |
} | |
} | |
else | |
{ | |
SaveDeliverParameters(); | |
v2 = -(int)&HID; | |
if ( (unsigned int)-(int)&HID >= 0x42000 ) | |
v2 = 0x42000; | |
KPageHeap::Initialize(&g_kernelPageHeap, (u32)&_slabheaps_start, v2 + 0x2000); | |
heap = (char *)KPageHeap::AllocateContiguous(&g_kernelPageHeap, 0x3Eu, 0); | |
if ( !heap ) | |
kernelpanic(); | |
KSlabHeap::Initialize(&g_eventAllocator.slabHeap, 0x28u, heap, 0x3138u); | |
g_eventAllocator.count = 0; | |
KSlabHeap::Initialize(&g_mutexAllocator.slabHeap, 0x2Cu, heap + 12600, 0xEA0u); | |
g_mutexAllocator.count = 0; | |
KSlabHeap::Initialize(&g_semaphoreAllocator.slabHeap, 0x2Cu, heap + 0x3FD8, 0xE48u); | |
g_semaphoreAllocator.count = 0; | |
KSlabHeap::Initialize(&g_timerAllocator.slabHeap, 0x3Cu, heap + 20000, 0xE10u); | |
g_timerAllocator.count = 0; | |
KSlabHeap::Initialize(&g_processAllocator.slabHeap, 0x270u, heap + 23600, 0x7290u); | |
g_processAllocator.count = 0; | |
KSlabHeap::Initialize(&g_threadAllocator.slabHeap, 0xB0u, heap + 52928, 0xCE40u); | |
g_threadAllocator.count = 0; | |
KSlabHeap::Initialize(&g_portAllocator.slabHeap, 0x48u, heap + 105728, 0x2B08u); | |
g_portAllocator.count = 0; | |
KSlabHeap::Initialize(&g_dmaObjectAllocator.slabHeap, 0x18u, heap + 116744, 0x180u); | |
g_dmaObjectAllocator.count = 0; | |
KSlabHeap::Initialize(&g_sharedMemoryAllocator.slabHeap, 0x28u, heap + 117128, 0x9D8u); | |
g_sharedMemoryAllocator.count = 0; | |
KSlabHeap::Initialize(&g_debugAllocator.slabHeap, 0xA0u, heap + 119648, 0x1E0u); | |
g_debugAllocator.count = 0; | |
KSlabHeap::Initialize(&g_sessionAllocator.slabHeap, 0x4Cu, heap + 120128, 0x6670u); | |
g_sessionAllocator.count = 0; | |
KSlabHeap::Initialize(&g_resourceLimitAllocator.slabHeap, 0x74u, heap + 146352, 0x248u); | |
g_resourceLimitAllocator.count = 0; | |
KSlabHeap::Initialize(&g_addressArbiterAllocator.slabHeap, 0x14u, heap + 146936, 0x400u); | |
g_addressArbiterAllocator.count = 0; | |
KSlabHeap::Initialize(&g_codeSetAllocator.slabHeap, 0x64u, heap + 147960, 0x1260u); | |
g_codeSetAllocator.count = 0; | |
KSlabHeap::Initialize(&g_linkedListNodeSlabHeap, 0xCu, heap + 152664, 0xC850u); | |
KSlabHeap::Initialize(&g_blockInfoSlabHeap, 8u, heap + 203944, 0x12C8u); | |
KSlabHeap::Initialize(&g_memoryBlockSlabHeap, 0x14u, heap + 208752, 0x86A0u); | |
KSlabHeap::Initialize(&g_threadLocalPageSlabHeap, 0x18u, heap + 243216, 0x600u); | |
KSlabHeap::Initialize(&g_objectNameSlabHeap, 0x10u, heap + 244752, 0x70u); | |
KSlabHeap::Initialize(&g_debugThreadSlabHeap, 0x18u, heap + 244864, 0xBE8u); | |
KSlabHeap::Initialize(&g_eventInfoSlabHeap, 0x38u, heap + 247912, 0xEA8u); | |
} | |
KSupervisorPageTable::UnmapIdentityAndInit(&g_supervisorPageTable, coreId); | |
cpu::SynchronizeAllCores(); | |
BindVariousAllCoreHelperIrqHandlers(coreId); | |
KObjectAllocator::Register(&g_threadAllocator, &p_clc->idleThread); | |
KInterruptTaskManager::Initialize(&p_clc->interruptTaskManagerInstance); | |
__enable_irq(); | |
KScheduler::Enable(current.clc.current.scheduler); | |
InitBindIrqHandlersWithThreads(coreId); | |
cpu::SynchronizeAllCores(); | |
if ( !coreId ) | |
{ | |
KWorkerTaskManager::Initialize(g_workerTaskManager, KWORKERTYPE_HIGH_PRIO, 1); | |
KWorkerTaskManager::Initialize(&g_workerTaskManager[1], KWORKERTYPE_LOW_PRIO, 16); | |
InitSharedKernelConfigPage(); | |
StartInitialProcesses(); | |
g_kernelState = KSTATE_RUNNING; | |
CreateKernelDiagnosticTable(); | |
} | |
cpu::SynchronizeAllCores(); | |
KThread::SetIdlePriority(current.clc.current.thread); | |
while ( 1 ) | |
__wfi(); | |
} | |
//----- (FFF005E0) -------------------------------------------------------- | |
void __noreturn HandleFiqException() | |
{ | |
int v0; // lr | |
u8 fiq_mask; // r9 | |
fiq_mask = CONFIG11.fiq_mask; | |
CONFIG11.fiq_mask = fiq_mask | 2; | |
MPCORE.gicd.sgir = 196623; | |
((void (*)(void))(v0 - 4))(); | |
} | |
// FFF005FC: variable 'v0' is possibly undefined | |
//----- (FFF00648) -------------------------------------------------------- | |
Result __fastcall KScheduler::Intialize(KScheduler *this, s32 coreId, KThread *idleThread) | |
{ | |
signed __int32 v7; // r1 | |
char cfgr; // r2 | |
this->coreId = coreId; | |
idleThread->alive = 1; | |
v7 = idleThread->coreId; | |
idleThread->coreId = this->coreId; | |
if ( v7 >= 0 ) | |
{ | |
cfgr = MPCORE.scu.cfgr; | |
if ( (cfgr & 3) + 1 > v7 ) | |
KVfpRegisterDumpHelper::DumpAndDisableVfpRegsForThread(idleThread, v7); | |
} | |
this->idleThread = idleThread; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
KScheduler::AddThread(this, idleThread); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
if ( coreId == 1 ) | |
{ | |
g_cpuTimeLimiterMode0.scheduler = this; | |
g_cpuTimeLimiterMode0.active = 0; | |
g_cpuTimeLimiterMode0.absoluteTimeInQuanta = 1LL; | |
g_cpuTimeLimiterMode1.scheduler = this; | |
g_cpuTimeLimiterMode1.active = 0; | |
g_cpuTimeLimiterMode1.absoluteTimeInQuanta = 1LL; | |
} | |
return KInterruptManager::BindInterrupt(&g_interruptManager, this, KINTNAME_SGI_SCHEDULER, this->coreId, 0, 0, 0); | |
} | |
//----- (FFF00728) -------------------------------------------------------- | |
void __fastcall KScheduler::Enable(KScheduler *this) | |
{ | |
unsigned int CPSR; // r4 | |
unsigned int *p_disableCount; // r2 | |
unsigned int v3; // r1 | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
p_disableCount = (unsigned int *)&this->disableCount; | |
do | |
v3 = __ldrex(p_disableCount); | |
while ( __strex(v3 - 1, p_disableCount) ); | |
if ( this->reschedule ) | |
KScheduler::SwitchThread(this, 0); | |
__set_CPSR(CPSR); | |
} | |
//----- (FFF00768) -------------------------------------------------------- | |
Result __fastcall KDmaManager::Initialize(KDmaManager *this) | |
{ | |
int chanId; // r4 | |
int coreId; // r7 | |
KDmaController::Initialize(); | |
for ( chanId = 0; chanId < 8; ++chanId ) | |
{ | |
AtomicBoolStore(&this->channelLocked[chanId], 0); | |
AtomicBoolStore(&this->interruptTaskEnqueued[chanId], 0); | |
KDmaController::EnableInterrupt(chanId); | |
} | |
coreId = __mrc(15, 0, 0, 0, 5) & 3; | |
KInterruptManager::BindInterrupt(&g_interruptManager, this, KINTNAME_N3DS_CDMA, coreId, 0, 1, 1); | |
return KInterruptManager::BindInterrupt(&g_interruptManager, this, KINTNAME_O3DS_CDMA_ABORT, coreId, 0, 0, 1);// BUG, should be the n3ds version (0x3b) | |
// This means the interrupt handler is bugged | |
} | |
//----- (FFF007FC) -------------------------------------------------------- | |
void CreateKernelDiagnosticTable(void) | |
{ | |
KernelDiagnosticTable *diagTable; // r0 | |
int v1; // [sp+0h] [bp-10h] BYREF | |
diagTable = (KernelDiagnosticTable *)((unsigned int)&v1 & ~0xFFFu); | |
diagTable->mainKernelRegionStart = 0x1FF80000; | |
diagTable->mainKernelRegionSize = 0x80000; | |
diagTable->unk_18 = 0; | |
diagTable->sizeofKAutoObject = 8; | |
diagTable->sizeofKThreadStackParams = 0xC8; | |
diagTable->clientPortOffset = 44; | |
diagTable->unk_1c = 0; | |
diagTable->pageManager = &g_memoryManager.pgMgr; | |
diagTable->hardwareTimer = &g_hardwareTimer; | |
diagTable->event.heap = g_eventAllocator.slabHeap.first; | |
diagTable->event.numElements = 315; | |
diagTable->event.elementSize = 40; | |
diagTable->event.head = &g_eventAllocator.slabHeap; | |
diagTable->mutex.heap = g_mutexAllocator.slabHeap.first; | |
diagTable->mutex.numElements = 85; | |
diagTable->mutex.elementSize = 44; | |
diagTable->mutex.head = &g_mutexAllocator.slabHeap; | |
diagTable->semaphore.heap = g_semaphoreAllocator.slabHeap.first; | |
diagTable->semaphore.numElements = 83; | |
diagTable->semaphore.elementSize = 44; | |
diagTable->semaphore.head = &g_semaphoreAllocator.slabHeap; | |
diagTable->timer.heap = g_timerAllocator.slabHeap.first; | |
diagTable->timer.numElements = 60; | |
diagTable->timer.elementSize = 60; | |
diagTable->timer.head = &g_timerAllocator.slabHeap; | |
diagTable->process.heap = g_processAllocator.slabHeap.first; | |
diagTable->process.numElements = 47; | |
diagTable->process.elementSize = 624; | |
diagTable->process.head = &g_processAllocator.slabHeap; | |
diagTable->thread.heap = g_threadAllocator.slabHeap.first; | |
diagTable->thread.numElements = 300; | |
diagTable->thread.elementSize = 176; | |
diagTable->thread.head = &g_threadAllocator.slabHeap; | |
diagTable->port.heap = g_portAllocator.slabHeap.first; | |
diagTable->port.numElements = 153; | |
diagTable->port.elementSize = 72; | |
diagTable->port.head = &g_portAllocator.slabHeap; | |
diagTable->dmaObject.heap = g_dmaObjectAllocator.slabHeap.first; | |
diagTable->dmaObject.numElements = 16; | |
diagTable->dmaObject.elementSize = 24; | |
diagTable->dmaObject.head = &g_dmaObjectAllocator.slabHeap; | |
diagTable->sharedMemory.heap = g_sharedMemoryAllocator.slabHeap.first; | |
diagTable->sharedMemory.numElements = 63; | |
diagTable->sharedMemory.elementSize = 40; | |
diagTable->sharedMemory.head = &g_sharedMemoryAllocator.slabHeap; | |
diagTable->session.heap = g_sessionAllocator.slabHeap.first; | |
diagTable->session.numElements = 345; | |
diagTable->session.elementSize = 76; | |
diagTable->session.head = &g_sessionAllocator.slabHeap; | |
diagTable->resourceLimit.heap = g_resourceLimitAllocator.slabHeap.first; | |
diagTable->resourceLimit.numElements = 5; | |
diagTable->resourceLimit.elementSize = 116; | |
diagTable->resourceLimit.head = &g_resourceLimitAllocator.slabHeap; | |
diagTable->addressArbiter.heap = g_addressArbiterAllocator.slabHeap.first; | |
diagTable->addressArbiter.numElements = 51; | |
diagTable->addressArbiter.elementSize = 20; | |
diagTable->addressArbiter.head = &g_addressArbiterAllocator.slabHeap; | |
diagTable->codeSet.heap = g_codeSetAllocator.slabHeap.first; | |
diagTable->codeSet.numElements = 47; | |
diagTable->codeSet.elementSize = 100; | |
diagTable->codeSet.head = &g_codeSetAllocator.slabHeap; | |
diagTable->linkedListNode.heap = g_linkedListNodeSlabHeap.first; | |
diagTable->linkedListNode.numElements = 4273; | |
diagTable->linkedListNode.elementSize = 12; | |
diagTable->linkedListNode.head = &g_linkedListNodeSlabHeap; | |
diagTable->blockInfo.heap = g_blockInfoSlabHeap.first; | |
diagTable->blockInfo.numElements = 601; | |
diagTable->blockInfo.elementSize = 8; | |
diagTable->blockInfo.head = &g_blockInfoSlabHeap; | |
diagTable->memoryBlock.heap = g_memoryBlockSlabHeap.first; | |
diagTable->memoryBlock.numElements = 1723; | |
diagTable->memoryBlock.elementSize = 20; | |
diagTable->memoryBlock.head = &g_memoryBlockSlabHeap; | |
diagTable->threadLocalPage.heap = g_threadLocalPageSlabHeap.first; | |
diagTable->threadLocalPage.numElements = 64; | |
diagTable->threadLocalPage.elementSize = 24; | |
diagTable->threadLocalPage.head = &g_threadLocalPageSlabHeap; | |
diagTable->objectName.heap = g_objectNameSlabHeap.first; | |
diagTable->objectName.numElements = 7; | |
diagTable->objectName.elementSize = 16; | |
diagTable->objectName.head = &g_objectNameSlabHeap; | |
} | |
//----- (FFF00B00) -------------------------------------------------------- | |
void __fastcall KWorkerTaskManager::Initialize(KWorkerTaskManager *this, KWorkerType type, s32 priority) | |
{ | |
unsigned int v5; // r2 | |
bool v6; // zf | |
unsigned int v7; // r3 | |
unsigned int v8; // r1 | |
unsigned int v9; // r2 | |
bool v10; // zf | |
unsigned int v11; // r3 | |
KSynchronizationObject *v12; // r0 | |
KThread *v13; // r7 | |
KThread *v14; // r0 | |
void *stack; // r8 | |
this->type = type; | |
this->first = 0; | |
this->last = 0; | |
this->active = 0; | |
v5 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v6 = v5 == 0; | |
if ( v5 ) | |
v7 = __strex(v5, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v7 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v5 ) | |
v6 = v7 == 0; | |
if ( !v6 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
do | |
v8 = __ldrex(&g_memoryManager.pgMgr.kernelMemoryUsage); | |
while ( __strex(v8 + 4096, &g_memoryManager.pgMgr.kernelMemoryUsage) ); | |
stack = KPageHeap::AllocateContiguous(&g_memoryManager.baseHeap, 1u, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
v9 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v10 = v9 == 0; | |
if ( v9 ) | |
v11 = __strex(v9, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v11 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v9 ) | |
v10 = v11 == 0; | |
if ( !v10 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)stack, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
v12 = (KSynchronizationObject *)KSlabHeap::Allocate(&g_threadAllocator.slabHeap); | |
v13 = (KThread *)v12; | |
if ( v12 ) | |
{ | |
v14 = (KThread *)KSynchronizationObject::KSynchronizationObject(v12); | |
v14->KTimerTask::next = 0; | |
v14->KWorkerTask::next = 0; | |
v14->KInterruptTask::KInterruptHandler::__vftable = &KThread::vt_KInterruptTask; | |
v14->KInterruptTask::next = 0; | |
v14->KWorkerTask::__vftable = &KThread::vt_KWorkerTask; | |
v14->KTimerTask::__vftable = &KThread::vt_KTimerTask; | |
v14->KSynchronizationObject::KAutoObject::__vftable = &KThread::vt; | |
v14->shallTerminate = 0; | |
v14->synchronizationResult = 0xE7E3FFFF; | |
v14->wantedLightMutex = 0; | |
v14->syncObjectWaitAllList.link.next = (KSynchronizationObjectLinkedListNode *)&v14->syncObjectWaitAllList.link; | |
v14->syncObjectWaitAllList.count = 0; | |
v14->syncObjectWaitAllList.link.prev = (KSynchronizationObjectLinkedListNode *)&v14->syncObjectWaitAllList.link; | |
v14->heldMutexListRootNode = 0; | |
v14->mutexTryingToAcquireList.link.next = (KMutexLinkedListNode *)&v14->mutexTryingToAcquireList.link; | |
v14->mutexTryingToAcquireList.count = 0; | |
v14->mutexTryingToAcquireList.link.prev = (KMutexLinkedListNode *)&v14->mutexTryingToAcquireList.link; | |
v14->affinityMask = 0; | |
v14->owner = 0; | |
v14->context = 0; | |
KAutoObject::Initialize(v13); | |
} | |
this->handlingThread = v13; | |
KThread::Initialize( | |
v13, | |
(u32)KWorkerTaskManager::ThreadFunction, | |
(u32)this, | |
(u32)stack + 0x1000, | |
0, | |
priority, | |
1, | |
0, | |
KTHREAD_TYPE_KERNEL); | |
KObjectAllocator::Register(&g_threadAllocator, this->handlingThread); | |
KThread::PrepareToRun(this->handlingThread); | |
} | |
// FFF00B8C: conditional instruction was optimized away because r0.4==300 | |
// FFF00B94: conditional instruction was optimized away because r0.4==300 | |
// FFF00C34: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF00DBC) -------------------------------------------------------- | |
void __fastcall KInterruptTaskManager::Initialize(KInterruptTaskManager *this) | |
{ | |
KSynchronizationObject *v2; // r0 | |
KThread *v3; // r4 | |
KThread *v4; // r0 | |
v2 = (KSynchronizationObject *)KSlabHeap::Allocate(&g_threadAllocator.slabHeap); | |
v3 = (KThread *)v2; | |
if ( v2 ) | |
{ | |
v4 = (KThread *)KSynchronizationObject::KSynchronizationObject(v2); | |
v4->KTimerTask::next = 0; | |
v4->KWorkerTask::next = 0; | |
v4->KInterruptTask::next = 0; | |
v4->KWorkerTask::__vftable = &KThread::vt_KWorkerTask; | |
v4->KInterruptTask::KInterruptHandler::__vftable = &KThread::vt_KInterruptTask; | |
v4->KTimerTask::__vftable = &KThread::vt_KTimerTask; | |
v4->KSynchronizationObject::KAutoObject::__vftable = &KThread::vt; | |
v4->shallTerminate = 0; | |
v4->wantedLightMutex = 0; | |
v4->synchronizationResult = 0xE7E3FFFF; | |
v4->syncObjectWaitAllList.count = 0; | |
v4->syncObjectWaitAllList.link.next = (KSynchronizationObjectLinkedListNode *)&v4->syncObjectWaitAllList.link; | |
v4->heldMutexListRootNode = 0; | |
v4->syncObjectWaitAllList.link.prev = (KSynchronizationObjectLinkedListNode *)&v4->syncObjectWaitAllList.link; | |
v4->mutexTryingToAcquireList.count = 0; | |
v4->mutexTryingToAcquireList.link.next = (KMutexLinkedListNode *)&v4->mutexTryingToAcquireList.link; | |
v4->mutexTryingToAcquireList.link.prev = (KMutexLinkedListNode *)&v4->mutexTryingToAcquireList.link; | |
v4->affinityMask = 0; | |
v4->owner = 0; | |
v4->context = 0; | |
KAutoObject::Initialize(v3); | |
} | |
this->handlingThread = v3; | |
KThread::InitializeCriticalKernelThread(v3, KInterruptTaskManager::ThreadFunction, this); | |
KObjectAllocator::Register(&g_threadAllocator, this->handlingThread); | |
KThread::PrepareToRun(this->handlingThread); | |
} | |
// FFF00DE4: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF00EA4) -------------------------------------------------------- | |
void __fastcall StartInitialProcesses() | |
{ | |
Cxi *currentCxi; // r6 | |
int v1; // r7 | |
KCodeSet *v2; // r0 | |
KCodeSet *v3; // r5 | |
s32 idealProcessor; // r9 | |
KSynchronizationObject *v5; // r0 | |
KProcess *v6; // r4 | |
KProcess *v7; // r0 | |
KProcess *p_process; // r0 | |
char cfgr; // r0 | |
InitialProcess v10; // [sp+0h] [bp-C0h] BYREF | |
u32 mainThreadPrio; // [sp+84h] [bp-3Ch] | |
KAffinityMask affinityMask; // [sp+88h] [bp-38h] BYREF | |
u32 mainThreadStackSize; // [sp+8Ch] [bp-34h] | |
KSynchronizationObject_vtbl *v14; // [sp+90h] [bp-30h] | |
KWorkerTask_vtbl *v15; // [sp+94h] [bp-2Ch] | |
currentCxi = (Cxi *)0xDFF00000; | |
v14 = &KProcess::vt; | |
v1 = 0; | |
v15 = &KProcess::vt_KWorkerTask; | |
do | |
{ | |
if ( (unsigned int)currentCxi >= 0xDFF357FC ) | |
break; | |
v2 = (KCodeSet *)KSlabHeap::Allocate(&g_codeSetAllocator.slabHeap); | |
v3 = v2; | |
if ( v2 ) | |
{ | |
KCodeSet::KCodeSet(v2); | |
KAutoObject::Initialize(v3); | |
} | |
v10.cxi = 0; | |
InitialProcess::InitialProcess(&v10, currentCxi); | |
InitialProcess::LoadCode(&v10, v3); | |
KObjectAllocator::Register(&g_codeSetAllocator, v3); | |
affinityMask = v10.affinityMask; | |
mainThreadPrio = v10.mainThreadPriority; | |
idealProcessor = v10.idealProcessor; | |
mainThreadStackSize = v10.mainThreadStackSize; | |
v5 = (KSynchronizationObject *)KSlabHeap::Allocate(&g_processAllocator.slabHeap); | |
v6 = (KProcess *)v5; | |
if ( v5 ) | |
{ | |
v7 = (KProcess *)KSynchronizationObject::KSynchronizationObject(v5); | |
v7->next = 0; | |
v7->KSynchronizationObject::KAutoObject::__vftable = v14; | |
v7->KWorkerTask::__vftable = v15; | |
v7->pgTable.mutex.lockingThread = 0; | |
v7->pgTable.mutex.numWaiters = 0; | |
v7->pgTable.mutex.ticketCount = 0; | |
v7->pgTable.memoryBlockMgr.blocks.link.next = (KMemoryBlockLinkedListNode *)&v7->pgTable.memoryBlockMgr.blocks.link; | |
v7->pgTable.memoryBlockMgr.blocks.count = 0; | |
v7->pgTable.memoryBlockMgr.blocks.link.prev = (KMemoryBlockLinkedListNode *)&v7->pgTable.memoryBlockMgr.blocks.link; | |
v7->kernAllocatedForProcess = 0; | |
v7->threadLocalPages.link.next = (KThreadLocalPageLinkedListNode *)&v7->threadLocalPages.link; | |
v7->threadLocalPages.count = 0; | |
v7->threadLocalPages.link.prev = (KThreadLocalPageLinkedListNode *)&v7->threadLocalPages.link; | |
v7->state = KPROCSTATE_CREATED; | |
v7->affinityMask = 0; | |
v7->threadCount = 0; | |
v7->capability.kernelFlags = 0; | |
v7->capability.intendedKernelVersion = 0; | |
p_process = CONTAINING_RECORD(KHandleTable::KHandleTable(&v7->handleTable), KProcess, handleTable); | |
p_process->unused_234 = 0; | |
p_process->unused_238 = 0LL; | |
p_process->unused_240 = 0LL; | |
p_process->unused_248 = 0LL; | |
p_process->unused_250 = 0LL; | |
p_process->unused_258 = 0LL; | |
p_process->unused_260 = 0LL; | |
p_process->unused_268 = 0LL; | |
KAutoObject::Initialize(v6); | |
} | |
KProcess::Initialize(v6, v3, v10.kernelCapsDescriptors, 0x1Cu); | |
KObjectAllocator::Register(&g_processAllocator, v6); | |
cfgr = MPCORE.scu.cfgr; | |
KAffinityMask::Normalize(&v6->affinityMask, &affinityMask, (cfgr & 3) + 1); | |
v6->idealProcessor = idealProcessor; | |
KProcess::Run(v6, mainThreadPrio, mainThreadStackSize); | |
++v1; | |
currentCxi = (Cxi *)((char *)currentCxi + InitialProcess::GetCxiSize(&v10)); | |
} | |
while ( v1 < 5 ); | |
memset((void *)0xDFF00000, 0, 0x35800u); | |
} | |
// FFF00EFC: conditional instruction was optimized away because r0.4!=0 | |
// FFF00F7C: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF010E0) -------------------------------------------------------- | |
void __fastcall ParseDeliverArgs(FcramLayout *layout) | |
{ | |
u8 bootEnv; // r0 | |
int v3; // r7 | |
int v4; // r2 | |
int v5; // r0 | |
u32 systemSize; // r2 | |
u32 v7; // r0 | |
bootEnv = crt0::FetchArm9Info_veneer()[2]; | |
if ( (bootEnv & 1) != 0 && (bootEnv & 6) == 0 ) | |
{ | |
if ( MEMORY[0x1FFA0438] != 0xFFFF | |
|| (v3 = MEMORY[0x1FFA043C], MEMORY[0x1FFA043C] = 0, crc32((void *)0x1FFA0400, 0x140u, 0xFFFFFFFF) != v3) ) | |
{ | |
memset((void *)0x1FFA0000, 0, 0x1000u); | |
} | |
} | |
v4 = 0x7C00000; | |
if ( MEMORY[0x1FFA0438] == 0xFFFF ) | |
{ | |
v5 = MEMORY[0x1FFA0400]; | |
if ( MEMORY[0x1FFA0400] == 7 ) | |
{ | |
v4 = 0xB200000; | |
layout->baseSize = 0x2000000; | |
layout->applicationSize = 0xB200000; | |
} | |
else | |
{ | |
layout->applicationSize = 0x7C00000; | |
if ( v5 != 8 ) | |
LOBYTE(v5) = 6; | |
layout->baseSize = 0x2000000; | |
} | |
layout->systemSize = 0xE000000 - v4; | |
g_systemControl.appMemType = v5; | |
} | |
else | |
{ | |
layout->baseSize = 0x2000000; | |
layout->systemSize = 104857600; | |
layout->applicationSize = 0x7C00000; | |
g_systemControl.appMemType = 6; | |
} | |
systemSize = layout->systemSize; | |
v7 = layout->applicationSize - 0x20000000; | |
layout->applicationAddr = 0xE0000000; | |
layout->systemAddr = v7; | |
layout->baseAddr = v7 + systemSize; | |
} | |
//----- (FFF01204) -------------------------------------------------------- | |
void SaveDeliverParameters(void) | |
{ | |
unsigned int v0; // r2 | |
bool v1; // zf | |
unsigned int v2; // r3 | |
unsigned int v3; // r2 | |
unsigned int v4; // r2 | |
bool v5; // zf | |
unsigned int v6; // r3 | |
u8 *Arm9Info_veneer; // r0 | |
void *Contiguous; // r6 | |
v0 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v1 = v0 == 0; | |
if ( v0 ) | |
v2 = __strex(v0, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v2 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v0 ) | |
v1 = v2 == 0; | |
if ( !v1 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
do | |
v3 = __ldrex(&g_memoryManager.pgMgr.kernelMemoryUsage); | |
while ( __strex(v3 + 4096, &g_memoryManager.pgMgr.kernelMemoryUsage) ); | |
Contiguous = KPageHeap::AllocateContiguous(&g_memoryManager.baseHeap, 1u, 0); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
g_systemControl.deliverParamsPage = (u32)Contiguous; | |
v4 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v5 = v4 == 0; | |
if ( v4 ) | |
v6 = __strex(v4, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v6 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v4 ) | |
v5 = v6 == 0; | |
if ( !v5 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)Contiguous, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
qmemcpy((void *)g_systemControl.deliverParamsPage, (const void *)0x1FFA0000, 0x1000u); | |
Arm9Info_veneer = crt0::FetchArm9Info_veneer(); | |
g_systemControl.unitInfo = Arm9Info_veneer[1]; | |
g_systemControl.bootEnv = Arm9Info_veneer[2]; | |
g_systemControl.deliverParamsSaved = 1; | |
} | |
// FFF01278: conditional instruction was optimized away because r0.4==300 | |
// FFF01280: conditional instruction was optimized away because r0.4==300 | |
//----- (FFF01404) -------------------------------------------------------- | |
void InitSharedKernelConfigPage(void) | |
{ | |
int isSafeModeComboPressed; // r12 | |
KernelSharedConfig *v1; // r0 | |
bool isDevUnitWithJtag; // zf | |
u32 appMemType; // r3 | |
u32 deliverParamsPage; // r2 | |
int v5; // r1 | |
u32 v6; // r6 | |
u8 kernelRevisionVersion; // r2 | |
u8 kernelMinorVersion; // r3 | |
u8 kernelMajorVersion; // r12 | |
u32 sysCoreVer; // r4 | |
u32 kernelCtrSdkVersion; // r5 | |
isSafeModeComboPressed = 0; | |
v1 = g_kernelSharedConfigPagePtr; | |
if ( (g_systemControl.bootEnv & 1) == 0 && g_systemControl.hid->pad == (u16)~0xF341 ) | |
isSafeModeComboPressed = 1; | |
g_kernelSharedConfigPagePtr->kernelBuildVersion = 0; | |
v1->kernelRevisionVersion = 0; | |
v1->kernelMinorVersion = 57; | |
v1->kernelMajorVersion = 2; | |
v1->updateFlag = isSafeModeComboPressed; | |
v1->sysCoreVer = 2; | |
LODWORD(v1->nsTid) = 0; | |
HIDWORD(v1->nsTid) = 0; | |
v1->envInfo = 0; | |
v1->unitInfo = g_systemControl.unitInfo; | |
v1->bootEnv = g_systemControl.bootEnv; | |
v1->kernelCtrSdkVersion = 0xF426; // sdk version | |
if ( g_systemControl.unitInfo ) | |
{ | |
g_systemControl.targetSystem.isDevUnit = 1; | |
} | |
else | |
{ | |
g_systemControl.targetSystem.isDevUnit = 0; | |
v1->envInfo = 1; | |
} | |
isDevUnitWithJtag = g_systemControl.unitInfo == 2; | |
if ( g_systemControl.unitInfo != 2 ) | |
isDevUnitWithJtag = g_systemControl.unitInfo == 3; | |
if ( isDevUnitWithJtag ) | |
{ | |
g_systemControl.targetSystem.userExceptionHandlersEnabled = 1; | |
g_systemControl.targetSystem.kernelPanicOnUserBreak = 1; | |
} | |
else | |
{ | |
g_systemControl.targetSystem.userExceptionHandlersEnabled = 0; | |
g_systemControl.targetSystem.kernelPanicOnUserBreak = 0; | |
} | |
if ( (__mrc(14, 0, 0, 1, 0) & 0x4000) != 0 ) // jtag connected | |
v1->envInfo |= 2u; | |
v1->nsTid = 0x4013000008002LL; | |
appMemType = g_systemControl.appMemType; | |
deliverParamsPage = g_systemControl.deliverParamsPage; | |
if ( g_systemControl.appMemType == 7 ) | |
v5 = 0xB200000; | |
else | |
v5 = 0x7C00000; | |
v6 = *(_DWORD *)(g_systemControl.deliverParamsPage + 0x400); | |
v1->appMemAlloc = v5; | |
v1->sysMemAlloc = 0xE000000 - v5; | |
v1->baseMemAlloc = 0x2000000; | |
v1->appMemType = appMemType; | |
v1->firmlaunchFlags = v6; | |
if ( *(_DWORD *)(deliverParamsPage + 0x438) == 0xFFFF && (*(_DWORD *)(deliverParamsPage + 0x400) & 0x100) != 0 )// "FIRM" fields | |
{ | |
v1->firmBuildVersion = *(_BYTE *)(deliverParamsPage + 0x410); | |
v1->firmRevisionVersion = *(_BYTE *)(deliverParamsPage + 0x411); | |
v1->firmMinorVersion = *(_BYTE *)(deliverParamsPage + 0x412); | |
v1->firmMajorVersion = *(_BYTE *)(deliverParamsPage + 0x413); | |
v1->firmCtrSdkVersion = *(_DWORD *)(deliverParamsPage + 0x418); | |
v1->firmSysCoreVer = *(_DWORD *)(deliverParamsPage + 0x414); | |
} | |
else | |
{ | |
kernelRevisionVersion = v1->kernelRevisionVersion; | |
kernelMinorVersion = v1->kernelMinorVersion; | |
kernelMajorVersion = v1->kernelMajorVersion; | |
sysCoreVer = v1->sysCoreVer; | |
kernelCtrSdkVersion = v1->kernelCtrSdkVersion; | |
v1->firmBuildVersion = v1->kernelBuildVersion; | |
v1->firmRevisionVersion = kernelRevisionVersion; | |
v1->firmMinorVersion = kernelMinorVersion; | |
v1->firmMajorVersion = kernelMajorVersion; | |
v1->firmSysCoreVer = sysCoreVer; | |
v1->firmCtrSdkVersion = kernelCtrSdkVersion; | |
} | |
} | |
// FFF2F0D4: using guessed type KernelSharedConfig *g_kernelSharedConfigPagePtr; | |
//----- (FFF015BC) -------------------------------------------------------- | |
void __fastcall KCoreLocalContext::InitializeCurrent(s32 coreId) | |
{ | |
KCoreLocalContext *p_clc; // r4 | |
KThread *__shifted(KCoreLocalContext,0x18) schedThread; // r0 | |
KScheduler *__shifted(KCoreLocalContext,0xC8) v3; // r0 | |
unsigned __int64 *unused_300; // r2 | |
p_clc = &g_coreLocalRegions[coreId].clc; | |
if ( p_clc ) | |
{ | |
memset(p_clc, 0, 0xB78u); | |
p_clc->current.threadWithVfp = 0; | |
schedThread = (KThread *__shifted(KCoreLocalContext,0x18))KSynchronizationObject::KSynchronizationObject(&p_clc->idleThread); | |
ADJ(schedThread)->idleThread.next = 0; | |
ADJ(schedThread)->idleThread.next = 0; | |
ADJ(schedThread)->idleThread.__vftable = &KThread::vt_KInterruptTask; | |
ADJ(schedThread)->idleThread.next = 0; | |
ADJ(schedThread)->idleThread.__vftable = &KThread::vt_KTimerTask; | |
ADJ(schedThread)->idleThread.__vftable = &KThread::vt; | |
ADJ(schedThread)->idleThread.__vftable = &KThread::vt_KWorkerTask; | |
ADJ(schedThread)->idleThread.shallTerminate = 0; | |
ADJ(schedThread)->idleThread.synchronizationResult = 0xE7E3FFFF; | |
ADJ(schedThread)->idleThread.wantedLightMutex = 0; | |
ADJ(schedThread)->idleThread.syncObjectWaitAllList.link.next = (KSynchronizationObjectLinkedListNode *)&ADJ(schedThread)->idleThread.syncObjectWaitAllList.link; | |
ADJ(schedThread)->idleThread.syncObjectWaitAllList.count = 0; | |
ADJ(schedThread)->idleThread.syncObjectWaitAllList.link.prev = (KSynchronizationObjectLinkedListNode *)&ADJ(schedThread)->idleThread.syncObjectWaitAllList.link; | |
ADJ(schedThread)->idleThread.heldMutexListRootNode = 0; | |
ADJ(schedThread)->idleThread.mutexTryingToAcquireList.link.next = (KMutexLinkedListNode *)&ADJ(schedThread)->idleThread.mutexTryingToAcquireList.link; | |
ADJ(schedThread)->idleThread.mutexTryingToAcquireList.count = 0; | |
ADJ(schedThread)->idleThread.mutexTryingToAcquireList.link.prev = (KMutexLinkedListNode *)&ADJ(schedThread)->idleThread.mutexTryingToAcquireList.link; | |
ADJ(schedThread)->idleThread.affinityMask = 0; | |
ADJ(schedThread)->idleThread.owner = 0; | |
ADJ(schedThread)->idleThread.context = 0; | |
v3 = KScheduler::KScheduler(&ADJ(schedThread)->schedulerInstance); | |
ADJ(v3)->interruptTaskManagerInstance.first = 0; | |
ADJ(v3)->interruptTaskManagerInstance.last = 0; | |
v3 = (KScheduler *__shifted(KCoreLocalContext,0xC8))((char *)v3 + 0x238); | |
ADJ(v3)->schedulerInstance.__vftable = 0; // unused@0x300 | |
ADJ(v3)->schedulerInstance.next = 0; | |
} | |
p_clc->current.thread = 0; | |
p_clc->current.process = 0; | |
unused_300 = (unsigned __int64 *)p_clc->unused_300; | |
p_clc->current.scheduler = &p_clc->schedulerInstance; | |
p_clc->current.interruptTaskManager = &p_clc->interruptTaskManagerInstance; | |
do | |
__ldrexd(unused_300); | |
while ( __strexd(0LL, unused_300) ); | |
*(_DWORD *)&p_clc->unused_300[8] = 0; | |
*(_DWORD *)&p_clc->unused_300[12] = 0; | |
*(_DWORD *)&p_clc->unused_300[16] = 0; | |
*(_DWORD *)&p_clc->unused_300[20] = 0; | |
*(_DWORD *)&p_clc->unused_300[24] = 0; | |
*(_DWORD *)&p_clc->unused_300[28] = 0; | |
*(_DWORD *)&p_clc->unused_300[40] = 0; | |
*(_DWORD *)&p_clc->unused_300[44] = 0; | |
*(_DWORD *)&p_clc->unused_300[48] = 0; | |
*(_DWORD *)&p_clc->unused_300[52] = 0; | |
*(_DWORD *)&p_clc->unused_300[56] = 0; | |
*(_DWORD *)&p_clc->unused_300[60] = 0; | |
*(_DWORD *)&p_clc->unused_300[68] = 0; | |
*(_DWORD *)&p_clc->unused_300[96] = 0; | |
*(_DWORD *)&p_clc->unused_300[64] = 0; | |
*(_DWORD *)&p_clc->unused_300[108] = 0; | |
*(_DWORD *)&p_clc->unused_300[100] = 0; | |
*(_DWORD *)&p_clc->unused_300[104] = 0; | |
*(_DWORD *)&p_clc->unused_300[88] = 0; | |
*(_DWORD *)&p_clc->unused_300[92] = 0; | |
*(_DWORD *)&p_clc->unused_300[72] = 0; | |
*(_DWORD *)&p_clc->unused_300[76] = 0; | |
*(_DWORD *)&p_clc->unused_300[80] = 0; | |
*(_DWORD *)&p_clc->unused_300[84] = 0; | |
} | |
//----- (FFF01764) -------------------------------------------------------- | |
void AllocateSharedConfigPages(void) | |
{ | |
KernelSharedConfig *v0; // r9 | |
unsigned int v1; // r2 | |
bool v2; // zf | |
unsigned int v3; // r3 | |
u32 v4; // r8 | |
unsigned int v5; // r2 | |
bool v6; // zf | |
unsigned int v7; // r3 | |
g_kernelSharedConfigPagePtr = (KernelSharedConfig *)KMemoryManager::AllocateContiguous( | |
&g_memoryManager, | |
1u, | |
0, | |
MEMOP_REGION_BASE_KERNEL); | |
g_userSharedConfigPagePtr = KMemoryManager::AllocateContiguous(&g_memoryManager, 1u, 0, MEMOP_REGION_BASE_KERNEL); | |
v0 = g_kernelSharedConfigPagePtr; | |
v1 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v2 = v1 == 0; | |
if ( v1 ) | |
v3 = __strex(v1, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v3 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v1 ) | |
v2 = v3 == 0; | |
if ( !v2 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)v0, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
v4 = g_userSharedConfigPagePtr; | |
v5 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v6 = v5 == 0; | |
if ( v5 ) | |
v7 = __strex(v5, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v7 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v5 ) | |
v6 = v7 == 0; | |
if ( !v6 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, v4, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
} | |
// FFF2F0D4: using guessed type KernelSharedConfig *g_kernelSharedConfigPagePtr; | |
//----- (FFF01870) -------------------------------------------------------- | |
void __fastcall KLevel2TranslationTableAllocator::Initialize(u32 cpuId) | |
{ | |
u32 v1; // r9 | |
u16 *refcounts; // r7 | |
int v3; // r0 | |
unsigned int v4; // r1 | |
int v5; // r1 | |
u32 v6; // r0 | |
u16 *v7; // r2 | |
int v8; // r1 | |
u16 *v9; // r2 | |
u32 Contiguous; // r5 | |
unsigned int v11; // r1 | |
bool v12; // zf | |
int i; // r7 | |
KLevel2TranslationTable *v14; // r0 | |
KLevel2TranslationTable *rootNode; // r1 | |
if ( !cpuId ) | |
{ | |
g_level2TtblAllocator.baseRegionStart = g_memoryManager.baseHeap.regionStart; | |
g_level2TtblAllocator.baseRegionSize = g_memoryManager.baseHeap.regionSize; | |
v1 = g_memoryManager.baseHeap.regionSize >> 21; | |
refcounts = (u16 *)KMemoryManager::AllocateContiguous( | |
&g_memoryManager, | |
g_memoryManager.baseHeap.regionSize >> 21,// BUG: this is not rounded up | |
// | |
// this prevent rosalina from setting BASE to a non-2MB aligned region | |
// | |
// fuck this shit | |
0, | |
MEMOP_REGION_BASE_KERNEL); | |
if ( !refcounts ) | |
{ | |
v3 = -664795149; | |
LABEL_36: | |
if ( v3 < 0 ) | |
kernelpanic(); | |
return; | |
} | |
v4 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( v4 ) | |
{ | |
__strex(v4, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
} | |
else if ( !__strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex) ) | |
{ | |
goto LABEL_8; | |
} | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
LABEL_8: | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)refcounts, v1); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
g_level2TtblAllocator.refcounts = refcounts; | |
if ( g_level2TtblAllocator.baseRegionSize >= 0x400 ) | |
{ | |
v5 = 0; | |
v6 = g_level2TtblAllocator.baseRegionSize << 21 >> 31; | |
if ( v6 == 1 ) | |
*refcounts = 0; | |
if ( v6 == 1 ) | |
v5 = 1; | |
for ( ; v6 < g_level2TtblAllocator.baseRegionSize >> 10; *v9 = 0 ) | |
{ | |
v6 += 2; | |
v7 = &g_level2TtblAllocator.refcounts[v5]; | |
v8 = v5 + 1; | |
*v7 = 0; | |
v9 = &g_level2TtblAllocator.refcounts[v8]; | |
v5 = v8 + 1; | |
} | |
} | |
g_level2TtblAllocator.numAvailable = 0; | |
Contiguous = KMemoryManager::AllocateContiguous(&g_memoryManager, 0x20u, 0, MEMOP_REGION_BASE_KERNEL); | |
if ( Contiguous ) | |
{ | |
v11 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v12 = v11 == 0; | |
if ( v11 ) | |
__strex(v11, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v11 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( v12 ) | |
v12 = v11 == 0; | |
if ( !v12 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, Contiguous, 0x20u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
for ( i = 0; i < 128; ++i ) | |
{ | |
v14 = (KLevel2TranslationTable *)(Contiguous + (i << 10)); | |
if ( v14 ) | |
{ | |
v14->next = 0; | |
v14->prev = 0; | |
} | |
rootNode = g_level2TtblAllocator.rootNode; | |
if ( g_level2TtblAllocator.rootNode ) | |
{ | |
v14->prev = g_level2TtblAllocator.rootNode; | |
rootNode->next->prev = v14; | |
v14->next = rootNode->next; | |
rootNode->next = v14; | |
} | |
else | |
{ | |
v14->prev = v14; | |
v14->next = v14; | |
} | |
g_level2TtblAllocator.rootNode = v14; | |
} | |
g_level2TtblAllocator.numAvailable += 128; | |
} | |
v3 = 0; | |
goto LABEL_36; | |
} | |
} | |
//----- (FFF01A8C) -------------------------------------------------------- | |
void __fastcall KHardwareTimer::Initialize(KHardwareTimer *this, s32 coreId) | |
{ | |
int v2; // r8 | |
char cfgr; // r0 | |
int v4; // r10 | |
_DWORD *v5; // r0 | |
if ( coreId == 1 ) | |
{ | |
if ( KSystemControl::IsLgr2Capable() ) | |
{ | |
g_timerPrescaler = 2; | |
g_wdPrescaler = 2; | |
} | |
v2 = 0; | |
cfgr = MPCORE.scu.cfgr; | |
v4 = (cfgr & 3) + 1; | |
if ( v4 > 0 ) // initialize all timer and wdt blocks (but only use the one for core 1) | |
{ | |
do | |
{ | |
v5 = (_DWORD *)((v2 << 8) + 0xFFFEE734); | |
*(_DWORD *)((v2 << 8) + 0xFFFEE708) = 0; | |
*(_DWORD *)((v2 << 8) + 0xFFFEE700) = 0; | |
*(_DWORD *)((v2 << 8) + 0xFFFEE704) = 0; | |
*(_DWORD *)((v2 << 8) + 0xFFFEE70C) = 1;// clear event flag (timer) | |
*v5 = 0x12345678; // disable watchdog mode | |
*v5 = 0x87654321; | |
*(_DWORD *)((v2 << 8) + 0xFFFEE728) = 0; | |
*(_DWORD *)((v2 << 8) + 0xFFFEE720) = 0; | |
*(_DWORD *)((v2 << 8) + 0xFFFEE724) = 0; | |
*(_DWORD *)((v2 << 8) + 0xFFFEE72C) = 1;// clear event flag (watchdog) | |
*(_DWORD *)((v2++ << 8) + 0xFFFEE730) = 0; | |
} | |
while ( v4 > v2 ); | |
} | |
this->innerTask.next = 0; | |
KInterruptManager::BindInterrupt(&g_interruptManager, this, KINTNAME_TIMER, 1, 0, 1, 0); | |
KInterruptManager::BindInterrupt(&g_interruptManager, this, KINTNAME_WDT, 1, 0, 0, 0); | |
this->counter = 0; | |
this->previousCounterOnInterrupt = 0; | |
MPCORE.timerWdtN[1].watchdogloadr = 0xFFFFFFFF; | |
MPCORE.timerWdtN[1].watchdogcontrolr = (g_wdPrescaler << 8) | 7;// | |
// wdt interrupt is always left enable, and we still need to keep track of the time when running KTimerTasks... | |
// | |
// timer interrupt is used for timer tasks | |
} | |
cpu::SynchronizeAllCores(); | |
} | |
//----- (FFF01C10) -------------------------------------------------------- | |
void __fastcall KSupervisorPageTable::UnmapIdentityAndInit(KSupervisorPageTable *this, u32 coreId) | |
{ | |
current.L1Table[0x1FF] = 0; | |
KPageTable::CleanInvalidateEntireDataCacheLocal(); | |
KPageTable::InvalidateEntireInstructionCacheLocal(); | |
__mcr(15, 0, 0, 8, 7, 0); | |
__mcr(15, 0, 0, 7, 5, 6); | |
__mcr(15, 0, 0, 7, 10, 4); | |
__mcr(15, 0, 0, 7, 5, 4); | |
if ( !coreId ) | |
KSupervisorPageTable::Initialize(this, current.L1Table, 0x40000000u, 0xFFFFF000); | |
} | |
//----- (FFF01C70) -------------------------------------------------------- | |
void __fastcall BindVariousAllCoreHelperIrqHandlers(s32 coreId) | |
{ | |
KInterruptManager::BindInterrupt( | |
&g_interruptManager, | |
&g_systemControlHelper, | |
KINTNAME_SGI_CONTROL_SYSTEM, | |
coreId, | |
0, | |
0, | |
0); | |
KTlbMaintenanceHelper::BindInterrupt(coreId); | |
KVfpRegisterDumpHelper::BindInterrupt(coreId); | |
} | |
//----- (FFF01CC0) -------------------------------------------------------- | |
void __fastcall InitBindIrqHandlersWithThreads(s32 coreId) | |
{ | |
unsigned int v2; // r2 | |
bool v3; // zf | |
unsigned int v4; // r3 | |
unsigned int v5; // r3 | |
unsigned int v6; // r2 | |
bool v7; // zf | |
unsigned int v8; // r3 | |
KSynchronizationObject *v9; // r0 | |
KThread *v10; // r5 | |
KThread *v11; // r0 | |
void *kernStackBottom; // r9 | |
v2 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v3 = v2 == 0; | |
if ( v2 ) | |
v4 = __strex(v2, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v4 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v2 ) | |
v3 = v4 == 0; | |
if ( !v3 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
do | |
v5 = __ldrex(&g_memoryManager.pgMgr.kernelMemoryUsage); | |
while ( __strex(v5 + 4096, &g_memoryManager.pgMgr.kernelMemoryUsage) ); | |
kernStackBottom = KPageHeap::AllocateContiguous(&g_memoryManager.baseHeap, 1u, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
v6 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v7 = v6 == 0; | |
if ( v6 ) | |
v8 = __strex(v6, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v8 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v6 ) | |
v7 = v8 == 0; | |
if ( !v7 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)kernStackBottom, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
v9 = (KSynchronizationObject *)KSlabHeap::Allocate(&g_threadAllocator.slabHeap); | |
v10 = (KThread *)v9; | |
if ( v9 ) | |
{ | |
v11 = (KThread *)KSynchronizationObject::KSynchronizationObject(v9); | |
v11->KTimerTask::next = 0; | |
v11->KWorkerTask::next = 0; | |
v11->KInterruptTask::KInterruptHandler::__vftable = &KThread::vt_KInterruptTask; | |
v11->KInterruptTask::next = 0; | |
v11->KWorkerTask::__vftable = &KThread::vt_KWorkerTask; | |
v11->KTimerTask::__vftable = &KThread::vt_KTimerTask; | |
v11->KSynchronizationObject::KAutoObject::__vftable = &KThread::vt; | |
v11->shallTerminate = 0; | |
v11->synchronizationResult = 0xE7E3FFFF; | |
v11->wantedLightMutex = 0; | |
v11->syncObjectWaitAllList.link.next = (KSynchronizationObjectLinkedListNode *)&v11->syncObjectWaitAllList.link; | |
v11->syncObjectWaitAllList.count = 0; | |
v11->syncObjectWaitAllList.link.prev = (KSynchronizationObjectLinkedListNode *)&v11->syncObjectWaitAllList.link; | |
v11->heldMutexListRootNode = 0; | |
v11->mutexTryingToAcquireList.link.next = (KMutexLinkedListNode *)&v11->mutexTryingToAcquireList.link; | |
v11->mutexTryingToAcquireList.count = 0; | |
v11->mutexTryingToAcquireList.link.prev = (KMutexLinkedListNode *)&v11->mutexTryingToAcquireList.link; | |
v11->affinityMask = 0; | |
v11->owner = 0; | |
v11->context = 0; | |
KAutoObject::Initialize(v10); | |
} | |
KThread::Initialize( | |
v10, | |
(u32)KCacheMaintenanceHelper::ThreadFunction, | |
(u32)&g_cacheMaintenanceHelper, | |
(u32)kernStackBottom + 0x1000, | |
0, | |
12, | |
coreId, | |
0, | |
KTHREAD_TYPE_KERNEL); | |
KObjectAllocator::Register(&g_threadAllocator, v10); | |
KSchedulerLock::Lock(&g_schedulerLock); | |
KThread::PrepareToRun(v10); | |
KThread::SetSchedulingState(v10, KTHREADSCHEDSTAT_PAUSED); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
g_cacheMaintenanceHelper.tasks[coreId].handlingThread = v10; | |
KInterruptManager::BindInterrupt( | |
&g_interruptManager, | |
&g_cacheMaintenanceHelper, | |
KINTNAME_SGI_CACHE_MAINTENANCE, | |
coreId, | |
0, | |
0, | |
0); | |
KInterruptManager::BindInterrupt(&g_interruptManager, &g_terminationHelper, KINTNAME_SGI_TERMINATION, coreId, 0, 0, 0); | |
KPerformanceCounterControlHelper::BindInterrupt(coreId); | |
} | |
// FFF01D40: conditional instruction was optimized away because r0.4==300 | |
// FFF01D48: conditional instruction was optimized away because r0.4==300 | |
// FFF01DEC: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF02000) -------------------------------------------------------- | |
Result KDebug::InitializeScheduledInOutState(void) | |
{ | |
SetEightBytesTo1(g_scheduledOut, 1); | |
return 0; | |
} | |
// FFF2F058: using guessed type bool g_scheduledOut[8]; | |
//----- (FFF0201C) -------------------------------------------------------- | |
void __fastcall KThread::SetIdlePriority(KThread *this) | |
{ | |
s32 dynamicPriority; // r2 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
dynamicPriority = this->dynamicPriority; | |
this->basePriority = 64; | |
this->dynamicPriority = 64; | |
KScheduler::AdjustThreadPriorityChanged(current.clc.current.scheduler, this, dynamicPriority); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
//----- (FFF02068) -------------------------------------------------------- | |
void __fastcall __noreturn HandlePrefetchAbortException(int a1, int a2, int a3, int a4, int a5) | |
{ | |
if ( (__get_SPSR() & 0x1F) != 16 ) | |
DispatchKernelExceptionWithRegdump((int)&a5, a2, a3, (int)DispatchPrefetchAbortException, a5); | |
__asm | |
{ | |
SRSDB SP!, #0x13 | |
CPS #0x13 | |
} | |
DispatchExceptionWithRegdump((int)&a5, a2, a3, a4, a5); | |
} | |
//----- (FFF020B0) -------------------------------------------------------- | |
void __fastcall HandleDataAbortException(int a1, int a2, int a3, int a4, int a5) | |
{ | |
int v5; // lr | |
unsigned int v6; // lr | |
void *v11; // r0 | |
v6 = v5 - 8; | |
if ( (__get_SPSR() & 0x1F) == 16 ) | |
{ | |
__asm | |
{ | |
SRSDB SP!, #0x13; user | |
CPS #0x13 | |
} | |
DispatchExceptionWithRegdump((int)&a5, a2, a3, a4, a5); | |
} | |
v11 = CopyBytesFromUser; | |
if ( v6 >= (unsigned int)CopyBytesFromUser ) | |
{ | |
v11 = KDmaAddress::ResetAddress; | |
if ( v6 < (unsigned int)KDmaAddress::ResetAddress ) | |
{ | |
__asm | |
{ | |
MSR SPSR_f, #0x40000000 | |
ADDS PC, LR, #4 | |
} | |
} | |
} | |
DispatchKernelExceptionWithRegdump((int)v11, a2, a3, (int)DispatchDataAbortException, a5); | |
} | |
// FFF020B0: variable 'v5' is possibly undefined | |
//----- (FFF02128) -------------------------------------------------------- | |
char *__fastcall HandleIrqException(int a1, int a2, int *a3, int a4, int a5) | |
{ | |
int *v5; // r12 | |
int v6; // lr | |
int v7; // lr | |
char *result; // r0 | |
int *v13; // [sp+0h] [bp-20h] | |
int v14; // [sp+4h] [bp-1Ch] | |
int *v15; // [sp+8h] [bp-18h] BYREF | |
int v16; // [sp+Ch] [bp-14h] | |
int *v17; // [sp+10h] [bp-10h] | |
int v18; // [sp+14h] [bp-Ch] BYREF | |
int *v19; // [sp+18h] [bp-8h] BYREF | |
int v20; // [sp+1Ch] [bp-4h] | |
v7 = v6 - 4; | |
if ( (__get_SPSR() & 0x1F) == 16 ) | |
{ | |
__asm | |
{ | |
SRSDB SP!, #0x13 | |
CPS #0x13 | |
} | |
v19 = &a5; | |
v20 = v7; | |
v13 = &a5; | |
v14 = a2; | |
v15 = a3; | |
v16 = a4; | |
v17 = v5; | |
IrqHandlerImpl(1); | |
__asm { RFEFD SP! } | |
} | |
v19 = &a5; | |
v20 = a2; | |
__asm | |
{ | |
CPS #0x13 | |
CPS #0x12 | |
} | |
result = (char *)&v18 + 3; | |
if ( (int)((int)&v18 - (((unsigned int)&v18 + 3) & 0xFFFFF000) + 3) >= 0x300 ) | |
{ | |
__asm | |
{ | |
SRSDB SP!, #0x13 | |
CPS #0x13 | |
} | |
v15 = v19; | |
v16 = v20; | |
v17 = a3; | |
v18 = a4; | |
v19 = v5; | |
v20 = v7; | |
v13 = (int *)&v15; | |
v14 = v7; | |
IrqHandlerImpl(0); | |
__asm { RFEFD SP! } | |
} | |
return result; | |
} | |
// FFF02128: variable 'v6' is possibly undefined | |
// FFF02154: variable 'v5' is possibly undefined | |
//----- (FFF021F0) -------------------------------------------------------- | |
// positive sp value has been detected, the output may be wrong! | |
void __fastcall __noreturn HandleSvcException(int a1, int a2, int a3, int a4, int a5, int a6, __int16 a7) | |
{ | |
int v7; // r4 | |
int v8; // lr | |
u32 v13; // r9 | |
int v14; // r1 | |
int v15; // r2 | |
int v16; // r3 | |
int v17; // r12 | |
int v18; // r0 | |
int (__fastcall *v19)(int, int, int, int, int, int, int, int, int); // r8 | |
int v23; // [sp-8h] [bp-48h] | |
int v25; // [sp-4h] [bp-44h] | |
int v26; // [sp+0h] [bp-40h] | |
int v27; // [sp+0h] [bp-40h] | |
int v28; // [sp+4h] [bp-3Ch] | |
int v29; // [sp+8h] [bp-38h] | |
int v30; // [sp+Ch] [bp-34h] | |
int v31; // [sp+10h] [bp-30h] | |
int v32; // [sp+14h] [bp-2Ch] | |
int v33; // [sp+14h] [bp-2Ch] | |
int v34; // [sp+18h] [bp-28h] | |
int v35; // [sp+1Ch] [bp-24h] | |
int v36; // [sp+20h] [bp-20h] | |
int v37; // [sp+24h] [bp-1Ch] | |
_BYTE *v38; // [sp+28h] [bp-18h] | |
int v39; // [sp+2Ch] [bp-14h] | |
_BYTE v40[8]; // [sp+30h] [bp-10h] BYREF | |
int v41; // [sp+38h] [bp-8h] | |
__asm { SRSDB SP!, #0x13 } | |
v38 = v40; | |
v39 = v8; | |
if ( (__get_SPSR() & 0x20) != 0 ) | |
LOWORD(v13) = *(_WORD *)(v8 - 2); | |
else | |
v13 = *(_DWORD *)(v8 - 4); | |
v13 = (unsigned __int8)v13; | |
if ( (unsigned __int8)v13 < 0x80u | |
&& (v19 = (int (__fastcall *)(int, int, int, int, int, int, int, int, int))svcTable[v13], | |
(*((unsigned __int8 *)&v41 + (v13 >> 3)) & (1 << (v13 & 7))) != 0) ) | |
{ | |
if ( HIBYTE(a7) ) | |
{ | |
v26 = v7; | |
__enable_irq(); | |
v18 = v19(a1, a2, a3, a4, a1, a2, a3, a4, v26); | |
} | |
else | |
{ | |
__enable_irq(); | |
v18 = ((int (__fastcall *)(int, int, int, int))v19)(a1, a2, a3, a4); | |
} | |
__disable_irq(); | |
} | |
else | |
{ | |
SvcStopPointOrInvalidId(v13); | |
v18 = 0; | |
if ( v32 ) | |
{ | |
v18 = v34; | |
v14 = v35; | |
v15 = v36; | |
v16 = v37; | |
v17 = v41; | |
} | |
} | |
while ( v39 ) | |
{ | |
v29 = v18; | |
v30 = v14; | |
v31 = v15; | |
v33 = v16; | |
v38 = (_BYTE *)v17; | |
v39 = 0; | |
v23 = v18; | |
v25 = v14; | |
v27 = v15; | |
v28 = v16; | |
PostSvcDpcHandler(); | |
v18 = v23; | |
v14 = v25; | |
v15 = v27; | |
v16 = v28; | |
if ( v39 ) | |
{ | |
v18 = v29; | |
v14 = v30; | |
v15 = v31; | |
v16 = v33; | |
v17 = (int)v38; | |
} | |
} | |
__asm { RFEFD SP! } | |
} | |
// FFF02248: positive sp value 10 has been found | |
// FFF022A0: conditional instruction was optimized away because %0x24.4==0 | |
// FFF021F4: variable 'v8' is possibly undefined | |
// FFF02240: variable 'v32' is possibly undefined | |
// FFF0227C: variable 'v7' is possibly undefined | |
// FFF022E4: variable 'v14' is possibly undefined | |
// FFF022E4: variable 'v15' is possibly undefined | |
// FFF022E4: variable 'v16' is possibly undefined | |
// FFF022E4: variable 'v17' is possibly undefined | |
// FFF0230C: using guessed type void *svcTable[126]; | |
//----- (FFF02504) -------------------------------------------------------- | |
int __fastcall HandleUndefinedInstructionException(int result, int a2, int a3, int a4, _DWORD *a5) | |
{ | |
__get_SPSR(); | |
if ( &a5 == (_DWORD **)16 ) | |
{ | |
__get_SPSR(); | |
if ( &a5 == (_DWORD **)32 ) | |
{ | |
__asm | |
{ | |
SRSDB SP!, #0x13 | |
CPS #0x13 | |
} | |
} | |
else | |
{ | |
__asm | |
{ | |
SRSDB SP!, #0x13 | |
CPS #0x13 | |
} | |
if ( (unsigned int)(16 * *a5 + 0x40000000) < 0x30000000 ) | |
{ | |
__asm { VMRS LR, FPEXC } | |
if ( (_LR & 0x40000000) == 0 ) | |
{ | |
EnableVfpAfterException(); | |
__asm { RFEFD SP! } | |
} | |
} | |
} | |
DispatchExceptionWithRegdump(result, a2, a3, a4, (int)a5); | |
} | |
return result; | |
} | |
//----- (FFF025A8) -------------------------------------------------------- | |
Result __fastcall InitialProcess::LoadCode(InitialProcess *this, KCodeSet *codeSet) | |
{ | |
ExHeader *exheader; // r5 | |
u32 v4; // r10 | |
u32 totalAllocSize; // r9 | |
char *decompressBuffer; // r7 | |
unsigned int v7; // r2 | |
bool v8; // zf | |
unsigned int v9; // r3 | |
ExeFs *exeFs; // r5 | |
char *v11; // r5 | |
unsigned int v12; // r2 | |
bool v13; // zf | |
unsigned int v14; // r3 | |
char *src; // [sp+0h] [bp-80h] | |
void *textLoadAddr; // [sp+4h] [bp-7Ch] BYREF | |
CodeSetInfo codeSetInfo; // [sp+8h] [bp-78h] BYREF | |
void *rodataLoadAddr; // [sp+48h] [bp-38h] BYREF | |
void *rwDataLoadAddr; // [sp+4Ch] [bp-34h] BYREF | |
memset(&codeSetInfo, 0, sizeof(codeSetInfo)); | |
codeSetInfo.name = this->exheader->info.sci.codeSetInfo.name; | |
exheader = this->exheader; | |
v4 = (this->exheader->info.sci.codeSetInfo.bssSize + 4095) >> 12; | |
src = (char *)&this->cxi->exheader + Ncch::ConvertSize(this->ncch->exeFsOffset, 0, this->ncch->flags[6] + 9); | |
InitialProcess::AllocateSegment( | |
this, | |
&textLoadAddr, | |
&codeSetInfo.text, | |
&exheader->info.sci.codeSetInfo.textCodeSectionInfo);// this is ctr-arm11 specific stuff | |
// | |
// LGY and Arm9 kernels load the code properly (no -nocodepadding) and honor IsCodeCompressed | |
InitialProcess::AllocateSegment( | |
this, | |
&rodataLoadAddr, | |
&codeSetInfo.rodata, | |
&this->exheader->info.sci.codeSetInfo.rodataSectionInfo); | |
InitialProcess::AllocateSegment( | |
this, | |
&rwDataLoadAddr, | |
&codeSetInfo.rwdata, | |
&this->exheader->info.sci.codeSetInfo.dataSectionInfo); | |
totalAllocSize = (this->exheader->info.sci.codeSetInfo.dataSectionInfo.size | |
+ this->exheader->info.sci.codeSetInfo.textCodeSectionInfo.size | |
+ this->exheader->info.sci.codeSetInfo.rodataSectionInfo.size | |
+ 4095) >> 12; | |
decompressBuffer = (char *)KMemoryManager::AllocateContiguous(&g_memoryManager, totalAllocSize, 1u, MEMOP_REGION_BASE); | |
v7 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v8 = v7 == 0; | |
if ( v7 ) | |
v9 = __strex(v7, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v9 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v7 ) | |
v8 = v9 == 0; | |
if ( !v8 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)decompressBuffer, totalAllocSize); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
exeFs = (ExeFs *)&this->cxi->signature[Ncch::ConvertSize(this->ncch->exeFsOffset, 0, this->ncch->flags[6] + 9)]; | |
memcpy(decompressBuffer, src, exeFs->fileHdrs[0].size); | |
LzssDecompress((u8 *)&decompressBuffer[exeFs->fileHdrs[0].size]); | |
memcpy(textLoadAddr, decompressBuffer, this->exheader->info.sci.codeSetInfo.textCodeSectionInfo.size); | |
v11 = &decompressBuffer[this->exheader->info.sci.codeSetInfo.textCodeSectionInfo.size]; | |
memcpy(rodataLoadAddr, v11, this->exheader->info.sci.codeSetInfo.rodataSectionInfo.size); | |
memcpy( | |
rwDataLoadAddr, | |
&v11[this->exheader->info.sci.codeSetInfo.rodataSectionInfo.size], | |
this->exheader->info.sci.codeSetInfo.dataSectionInfo.size); | |
v12 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v13 = v12 == 0; | |
if ( v12 ) | |
v14 = __strex(v12, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v14 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v12 ) | |
v13 = v14 == 0; | |
if ( !v13 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::FreeContiguous(&g_memoryManager.pgMgr, (u32)decompressBuffer, totalAllocSize, MEMOP_NONE); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
codeSetInfo.text_size_total = codeSetInfo.text.size; | |
codeSetInfo.ro_size_total = codeSetInfo.rodata.size; | |
codeSetInfo.rw_size_total = codeSetInfo.rwdata.size + v4; | |
KCodeSet::InitializeDirectly(codeSet, &codeSetInfo, (u32)textLoadAddr, (u32)rodataLoadAddr, (u32)rwDataLoadAddr); | |
return 0; | |
} | |
//----- (FFF0283C) -------------------------------------------------------- | |
KScheduler *__fastcall KScheduler::KScheduler(KScheduler *this) | |
{ | |
KScheduler *result; // r0 | |
this->__vftable = &KScheduler::vt; | |
this->next = 0; | |
this->disableCount = 1; | |
this->reschedule = 1; | |
this->rescheduleInterruptTaskMgrThread = 0; | |
this->triggerSgi = 0; | |
this->interruptTaskAdded = 0; | |
this->coreId = -1; | |
this->numThreads = 0; | |
this->idleThread = 0; | |
this->allThreads.link.prev = 0; | |
this->allThreads.link.next = 0; | |
result = CONTAINING_RECORD( | |
_aeabi_vec_ctor_nocookie_nodtor( | |
this->threadsByPrio, | |
(void *(__fastcall *)(void *))KThreadIntrusiveList::KThreadIntrusiveList, | |
8u, | |
0x40u), | |
KScheduler, | |
threadsByPrio); | |
result->prioBitfield[0] = 0; | |
result->prioBitfield[1] = 0; | |
return result; | |
} | |
//----- (FFF028A8) -------------------------------------------------------- | |
void __fastcall KMemoryManager::Intialize(KMemoryManager *this, FcramLayout *a2, u32 fcramAddr, u32 fcramSize) | |
{ | |
unsigned int *p_kernelMemoryUsage; // r12 | |
KPageHeap::Initialize(&this->applicationHeap, a2->applicationAddr, a2->applicationSize); | |
KPageHeap::Initialize(&this->systemHeap, a2->systemAddr, a2->systemSize); | |
KPageHeap::Initialize(&this->baseHeap, a2->baseAddr, a2->baseSize); | |
p_kernelMemoryUsage = &this->pgMgr.kernelMemoryUsage; | |
do | |
__ldrex(p_kernelMemoryUsage); | |
while ( __strex(0, p_kernelMemoryUsage) ); | |
this->pgMgr.unused_14_zero = 0; | |
this->pgMgr.mm = this; | |
this->pgMgr.memoryStartAddr = fcramAddr; | |
this->pgMgr.numPages = fcramSize >> 12; | |
KPageManager::Intialize(&this->pgMgr, fcramSize >> 12); | |
} | |
//----- (FFF02928) -------------------------------------------------------- | |
void __fastcall __noreturn KWorkerTaskManager::ThreadFunction(KWorkerTaskManager *this) | |
{ | |
KWorkerTask *first; // r5 | |
KWorkerTask *last; // r0 | |
bool v4; // zf | |
while ( 1 ) | |
{ | |
while ( 1 ) | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
first = this->first; | |
if ( first ) | |
break; | |
this->active = 0; | |
KThread::SetSchedulingState(this->handlingThread, KTHREADSCHEDSTAT_PAUSED); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
last = this->last; | |
v4 = last == first; | |
if ( last == first ) | |
{ | |
this->last = 0; | |
this->first = 0; | |
} | |
else | |
{ | |
last = first->next; | |
} | |
if ( !v4 ) | |
this->first = last; | |
first->next = 0; | |
this->active = 1; | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
first->DoWorkerTask(first); | |
} | |
} | |
//----- (FFF029B0) -------------------------------------------------------- | |
void __fastcall __noreturn KInterruptTaskManager::ThreadFunction(KInterruptTaskManager *this) | |
{ | |
unsigned int CPSR; // r4 | |
KInterruptTask *first; // r6 | |
KInterruptTask *v4; // r0 | |
KInterruptTask *last; // r1 | |
bool v6; // zf | |
while ( 1 ) | |
{ | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
first = this->first; | |
if ( this->first ) | |
goto LABEL_4; | |
__set_CPSR(CPSR); | |
KSchedulerLock::Lock(&g_schedulerLock); | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
first = this->first; | |
if ( this->first ) | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
LABEL_4: | |
v4 = this->first; | |
last = this->last; | |
v6 = this->first == last; | |
if ( this->first == last ) | |
{ | |
this->last = 0; | |
this->first = 0; | |
} | |
else | |
{ | |
v4 = v4->next; | |
} | |
if ( !v6 ) | |
this->first = v4; | |
__set_CPSR(CPSR); | |
first->DoTask(first); | |
} | |
else | |
{ | |
KThread::SetSchedulingState(this->handlingThread, KTHREADSCHEDSTAT_PAUSED); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
KScheduler::RescheduleByForce(current.clc.current.scheduler, 0); | |
__set_CPSR(CPSR); | |
} | |
} | |
} | |
//----- (FFF02A60) -------------------------------------------------------- | |
Result __fastcall KThread::InitializeCriticalKernelThread(KThread *this, void *ep, void *arg) | |
{ | |
unsigned int v4; // r2 | |
bool v5; // zf | |
unsigned int v6; // r3 | |
unsigned int v7; // r2 | |
void *stackBottom; // r8 | |
unsigned int v9; // r2 | |
v4 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v5 = v4 == 0; | |
if ( v4 ) | |
v6 = __strex(v4, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v6 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v4 ) | |
v5 = v6 == 0; | |
if ( !v5 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
do | |
v7 = __ldrex(&g_memoryManager.pgMgr.kernelMemoryUsage); | |
while ( __strex(v7 + 4096, &g_memoryManager.pgMgr.kernelMemoryUsage) ); | |
stackBottom = KPageHeap::AllocateContiguous(&g_memoryManager.baseHeap, 1u, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
if ( !stackBottom ) | |
kernelpanic(); | |
v9 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( v9 ) | |
{ | |
__strex(v9, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
LABEL_16: | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
goto LABEL_17; | |
} | |
if ( __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex) ) | |
goto LABEL_16; | |
LABEL_17: | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)stackBottom, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
return KThread::Initialize( | |
this, | |
(u32)ep, | |
(u32)arg, | |
(u32)stackBottom + 0x1000, | |
0, | |
0, | |
__mrc(15, 0, 0, 0, 5) & 3, | |
0, | |
KTHREAD_TYPE_KERNEL_CRITICAL); | |
} | |
// FFF02AD8: conditional instruction was optimized away because r0.4==300 | |
// FFF02AE0: conditional instruction was optimized away because r0.4==300 | |
//----- (FFF02C68) -------------------------------------------------------- | |
void KDmaController::Initialize(void) | |
{ | |
unsigned int v0; // r2 | |
bool v1; // zf | |
unsigned int v2; // r3 | |
int chanId; // r7 | |
unsigned int v4; // r2 | |
bool v5; // zf | |
unsigned int v6; // r3 | |
int v7; // r0 | |
CDMA.inten = 0xFFFFFFFF; // enable all channel interrupts, clear all | |
CDMA.intclr = 0xFFFFFFFF; | |
CDMA.inten = 0; // disable all channel interrupts | |
v0 = __ldrex((unsigned int *)&g_dmaManagerLock); | |
v1 = v0 == 0; | |
if ( v0 ) | |
v2 = __strex(v0, (unsigned int *)&g_dmaManagerLock); | |
else | |
v2 = __strex(*(_DWORD *)((int)&CDMA >> 3), (unsigned int *)&g_dmaManagerLock); | |
if ( !v0 ) | |
v1 = v2 == 0; | |
if ( !v1 ) | |
KLightMutex::LockImpl(&g_dmaManagerLock); | |
__mcr(15, 0, 0, 7, 10, 5); | |
CDMA.dbginst0 = 0x10000; // DMAKILL the manager thread | |
CDMA.dbginst1 = 0; | |
*(_DWORD *)((unsigned int)&CDMA.dbginst1 & ~8u) = 0;// dbgcmd (execute the instruction) | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_dmaManagerLock.lockingThread = 0; | |
if ( g_dmaManagerLock.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_dmaManagerLock); | |
for ( chanId = 0; chanId < 8; ++chanId ) | |
{ | |
v4 = __ldrex((unsigned int *)&g_dmaManagerLock); | |
v5 = v4 == 0; | |
if ( v4 ) | |
v6 = __strex(v4, (unsigned int *)&g_dmaManagerLock); | |
else | |
v6 = __strex(*(_DWORD *)((int)&CDMA >> 3), (unsigned int *)&g_dmaManagerLock); | |
if ( !v4 ) | |
v5 = v6 == 0; | |
if ( !v5 ) | |
KLightMutex::LockImpl(&g_dmaManagerLock); | |
__mcr(15, 0, 0, 7, 10, 5); | |
while ( (CDMA.dbgstatus & 1) != 0 ) // wait until instruction finished executing | |
; | |
do | |
{ | |
v7 = CDMA.dsr & 0xF; | |
if ( v7 == CDMA330THREAD_STATUS_FAULTING ) | |
kernelpanic(); | |
} | |
while ( v7 ); | |
CDMA.dbginst0 = ((char)chanId << 8) | 0x10001;// DMAKILL the channel thread | |
CDMA.dbginst1 = 0; | |
CDMA.dbgcmd = 0; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_dmaManagerLock.lockingThread = 0; | |
if ( g_dmaManagerLock.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_dmaManagerLock); | |
} | |
} | |
//----- (FFF02DA8) -------------------------------------------------------- | |
void __fastcall KDmaController::EnableInterrupt(s8 channelId) | |
{ | |
unsigned int v2; // r2 | |
bool v3; // zf | |
unsigned int v4; // r3 | |
u32 inten; // r3 | |
v2 = __ldrex((unsigned int *)&g_dmaManagerLock); | |
v3 = v2 == 0; | |
if ( v2 ) | |
v4 = __strex(v2, (unsigned int *)&g_dmaManagerLock); | |
else | |
v4 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_dmaManagerLock); | |
if ( !v2 ) | |
v3 = v4 == 0; | |
if ( !v3 ) | |
KLightMutex::LockImpl(&g_dmaManagerLock); | |
__mcr(15, 0, 0, 7, 10, 5); | |
inten = CDMA.inten; | |
CDMA.inten = inten | (1 << channelId); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_dmaManagerLock.lockingThread = 0; | |
if ( g_dmaManagerLock.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_dmaManagerLock); | |
} | |
//----- (FFF02E20) -------------------------------------------------------- | |
Result __fastcall KVfpRegisterDumpHelper::BindInterrupt(s32 coreId) | |
{ | |
return KInterruptManager::BindInterrupt( | |
&g_interruptManager, | |
&g_vfpRegisterDumpHelper.impls[coreId], | |
KINTNAME_SGI_DUMP_VFP_REGS, | |
coreId, | |
0, | |
0, | |
0); | |
} | |
//----- (FFF02E60) -------------------------------------------------------- | |
Result __fastcall KSupervisorPageTable::Initialize( | |
KSupervisorPageTable *this, | |
u32 *L1Table, | |
u32 addressSpaceStart, | |
u32 addressSpaceEnd) | |
{ | |
this->translationTableSize = 0x3000; | |
this->linearAddressRangeStart = 0; | |
this->asid = 0; | |
this->translationTableBase = 0; | |
this->isKernel = 1; | |
this->onlyUseSmallPages = 0; | |
this->addressSpaceStart = addressSpaceStart; | |
this->addressSpaceEnd = addressSpaceEnd; | |
this->L1Table = L1Table; | |
KMemoryBlockManager::Initialize(&this->memoryBlockMgr, addressSpaceStart, addressSpaceEnd); | |
return 0; | |
} | |
//----- (FFF02EB8) -------------------------------------------------------- | |
Result __fastcall KTlbMaintenanceHelper::BindInterrupt(s32 coreId) | |
{ | |
return KInterruptManager::BindInterrupt( | |
&g_interruptManager, | |
&g_tlbMaintenanceHelper.impls[coreId], | |
KINTNAME_SGI_TLB_MAINTENANCE, | |
coreId, | |
0, | |
0, | |
0); | |
} | |
//----- (FFF02EF8) -------------------------------------------------------- | |
void __fastcall KInterruptManager::InitializeCore(KInterruptManager *this, s32 coreId) | |
{ | |
int i; // lr | |
int v3; // r2 | |
int v4; // r12 | |
KInterruptEntry *v5; // r3 | |
int v6; // r2 | |
int v7; // r3 | |
KInterruptManager *v8; // r12 | |
int j; // r1 | |
_BYTE *v11; // r0 | |
_BYTE *v12; // r2 | |
u32 v13; // r0 | |
int totalNumInterrupts; // r6 | |
int totalNumInterruptLines; // r0 | |
BOOL v16; // r1 | |
int k; // r1 | |
int v18; // r2 | |
u32 v19; // r2 | |
int v20; // r0 | |
_BYTE *m; // r0 | |
_BYTE *v22; // r1 | |
_BYTE *v23; // r3 | |
_BYTE *v24; // r12 | |
_BYTE *v25; // r2 | |
if ( coreId == 1 ) | |
{ | |
for ( i = 0; i < 4; ++i ) | |
{ | |
v3 = 0; | |
v4 = 32; | |
do | |
{ | |
v5 = &this->privateInterrupts[i][v3]; | |
--v4; | |
v5->handler = 0; | |
v5->autoDisable_ManualClear = 0; | |
v5->disabled = 0; | |
++v3; | |
v5->priority = 15; | |
} | |
while ( v4 ); | |
} | |
v6 = 0; | |
v7 = 0x60; | |
do | |
{ | |
v8 = (KInterruptManager *)((char *)this + 8 * v6); | |
--v7; | |
v8->sharedInterrupts[0].handler = 0; | |
v8->sharedInterrupts[0].autoDisable_ManualClear = 0; | |
++v6; | |
v8->sharedInterrupts[0].disabled = 0; | |
} | |
while ( v7 ); | |
} | |
cpu::SynchronizeAllCores(); | |
MPCORE.gicd.ctlr = 0; | |
cpu::SynchronizeAllCores(); | |
MPCORE.gicd.icenabler[0] = 0xFFFFFFFF; | |
MPCORE.gicd.icpendr[0] = 0xFFFFFFFF; | |
for ( j = 0; j < 32; j += 2 ) | |
{ | |
v11 = (_BYTE *)(j + 0xFFFEF400); | |
v12 = (_BYTE *)(j + 0xFFFEF401); | |
*v11 = 0xF0; // min priority to all private interrupts, effectively disabling them | |
*v12 = 0xF0; | |
} | |
MPCORE.gicd.icfgr[0] = 0xAAAAAAAA; // N-N, edge-triggered, for all private interrupts | |
MPCORE.gicd.icfgr[1] = 0x28000000; // same for irqId 0x39 and 0x3a (old cdma faulting irq, new dma event) | |
if ( !coreId ) | |
{ | |
v13 = (32 * MPCORE.gicd.typer) & 0x3FF; | |
totalNumInterrupts = v13 + 32; | |
totalNumInterruptLines = (int)(v13 + 0x3F) / 32; | |
if ( totalNumInterruptLines > 1 ) | |
{ | |
v16 = (totalNumInterruptLines & 1) == 0; | |
if ( v16 ) | |
{ | |
MPCORE.gicd.icenabler[1] = 0xFFFFFFFF; | |
MPCORE.gicd.icpendr[1] = 0xFFFFFFFF; | |
} | |
} | |
else | |
{ | |
v16 = 0; | |
} | |
for ( k = v16 + 1; k < totalNumInterruptLines; *(_DWORD *)(v19 + 644) = 0xFFFFFFFF ) | |
{ | |
v18 = k; | |
k += 2; | |
v19 = (u32)&MPCORE.gicd + 4 * v18; | |
*(_DWORD *)(v19 + offsetof(Mp11GicDistributor, icenabler)) = 0xFFFFFFFF; | |
*(_DWORD *)(v19 + offsetof(Mp11GicDistributor, icpendr)) = 0xFFFFFFFF; | |
*(_DWORD *)(v19 + 0x184) = 0xFFFFFFFF; | |
} | |
if ( totalNumInterrupts > 32 ) | |
{ | |
v20 = totalNumInterrupts & 1; | |
if ( v20 == 1 ) | |
{ | |
MPCORE.gicd.ipriorityr[32] = 0xF0; | |
MPCORE.gicd.itargetsr[32] = 0; | |
} | |
} | |
else | |
{ | |
v20 = 0; | |
} | |
for ( m = (_BYTE *)(v20 + 32); (int)m < totalNumInterrupts; *v24 = 0 ) | |
{ | |
v22 = m - 0x10C00; // priority | |
v23 = m - 0x10BFF; | |
v24 = m - 0x107FF; // targets | |
v25 = m - 0x10800; | |
m += 2; | |
*v22 = 0xF0; | |
*v25 = 0; | |
*v23 = 0xF0; | |
} | |
MPCORE.gicd.icfgr[2] = 0x5550755; // Interrupts 0x00 to 0x1F: edge-triggered, N-N | |
// Interrupt 0x20: level-sensitive, 1-N | |
// Interrupt 0x21: level-sensitive, 1-N | |
// Interrupt 0x22: level-sensitive, 1-N | |
// Interrupt 0x23: level-sensitive, 1-N | |
// Interrupt 0x24: edge-triggered, 1-N | |
// Interrupt 0x25: level-sensitive, 1-N | |
// Interrupt 0x28: level-sensitive, 1-N | |
// Interrupt 0x29: level-sensitive, 1-N | |
// Interrupt 0x2a: level-sensitive, 1-N | |
// Interrupt 0x2b: level-sensitive, 1-N | |
// Interrupt 0x2c: level-sensitive, 1-N | |
// Interrupt 0x2d: level-sensitive, 1-N | |
// Interrupt 0x30: level-sensitive, 1-N | |
// Interrupt 0x31: level-sensitive, 1-N | |
// Interrupt 0x32: level-sensitive, 1-N | |
// Interrupt 0x33: level-sensitive, 1-N | |
// Interrupt 0x34: level-sensitive, 1-N | |
// Interrupt 0x35: level-sensitive, 1-N | |
// Interrupt 0x36: level-sensitive, 1-N | |
// Interrupt 0x37: level-sensitive, 1-N | |
// Interrupt 0x38: level-sensitive, 1-N | |
// Interrupt 0x39: level-sensitive, 1-N | |
// Interrupt 0x3a: level-sensitive, 1-N | |
// Interrupt 0x3b: level-sensitive, 1-N | |
// Interrupt 0x40: edge-triggered, 1-N | |
// Interrupt 0x41: edge-triggered, 1-N | |
// Interrupt 0x42: edge-triggered, 1-N | |
// Interrupt 0x43: edge-triggered, 1-N | |
// Interrupt 0x44: edge-triggered, 1-N | |
// Interrupt 0x45: edge-triggered, 1-N | |
// Interrupt 0x46: edge-triggered, 1-N | |
// Interrupt 0x48: edge-triggered, 1-N | |
// Interrupt 0x49: edge-triggered, 1-N | |
// Interrupt 0x4a: edge-triggered, 1-N | |
// Interrupt 0x4b: edge-triggered, 1-N | |
// Interrupt 0x4c: edge-triggered, 1-N | |
// Interrupt 0x4d: edge-triggered, 1-N | |
// Interrupt 0x4e: edge-triggered, 1-N | |
// Interrupt 0x4f: level-sensitive, 1-N | |
// Interrupt 0x50: edge-triggered, 1-N | |
// Interrupt 0x51: edge-triggered, 1-N | |
// Interrupt 0x52: edge-triggered, 1-N | |
// Interrupt 0x53: edge-triggered, 1-N | |
// Interrupt 0x54: edge-triggered, 1-N | |
// Interrupt 0x55: edge-triggered, 1-N | |
// Interrupt 0x56: edge-triggered, 1-N | |
// Interrupt 0x57: edge-triggered, 1-N | |
// Interrupt 0x58: level-sensitive, 1-N | |
// Interrupt 0x59: edge-triggered, 1-N | |
// Interrupt 0x5a: edge-triggered, 1-N | |
// Interrupt 0x5b: edge-triggered, 1-N | |
// Interrupt 0x5f: edge-triggered, 1-N | |
// Interrupt 0x60: edge-triggered, 1-N | |
// Interrupt 0x61: edge-triggered, 1-N | |
// Interrupt 0x64: edge-triggered, 1-N | |
// Interrupt 0x65: edge-triggered, 1-N | |
// Interrupt 0x66: edge-triggered, 1-N | |
// Interrupt 0x68: edge-triggered, 1-N | |
// Interrupt 0x69: edge-triggered, 1-N | |
// Interrupt 0x6a: edge-triggered, 1-N | |
// Interrupt 0x6b: edge-triggered, 1-N | |
// Interrupt 0x6c: edge-triggered, 1-N | |
// Interrupt 0x6d: edge-triggered, 1-N | |
// Interrupt 0x6e: edge-triggered, 1-N | |
// Interrupt 0x6f: edge-triggered, 1-N | |
// Interrupt 0x70: edge-triggered, 1-N | |
// Interrupt 0x71: edge-triggered, 1-N | |
// Interrupt 0x72: edge-triggered, 1-N | |
// Interrupt 0x73: edge-triggered, 1-N | |
// Interrupt 0x74: edge-triggered, 1-N | |
// Interrupt 0x75: edge-triggered, 1-N | |
// Interrupt 0x76: level-sensitive, 1-N | |
// Interrupt 0x77: level-sensitive, 1-N | |
// Interrupt 0x78: edge-triggered, 1-N | |
// Interrupt 0x79: level-sensitive, 1-N | |
// Interrupt 0x7a: level-sensitive, 1-N | |
// Interrupt 0x7b: level-sensitive, 1-N | |
// Interrupt 0x7c: level-sensitive, 1-N | |
// Interrupt 0x7d: level-sensitive, 1-N | |
MPCORE.gicd.icfgr[3] = 0x555555; | |
MPCORE.gicd.icfgr[4] = 0x7FFF3FFF; | |
MPCORE.gicd.icfgr[5] = 0xC0FDFFFF; | |
MPCORE.gicd.icfgr[6] = 0xFFFF3F0F; | |
MPCORE.gicd.icfgr[7] = 0x5575FFF; | |
MPCORE.gicd.ctlr = 1; // activate distributor | |
} | |
cpu::SynchronizeAllCores(); | |
MPCORE.gicc.bpr = 7; // no preemption | |
MPCORE.gicc.pmr = 0xF0; // all interrupts with priority >= 0xF(0) will assert the irq line | |
MPCORE.gicc.ctlr = 1; // activate interface | |
__asm | |
{ | |
CPSIE A | |
CPSIE F | |
} | |
} | |
// FFF03048: user specified stroff has not been processed: Mp11GicDistributor offset 388 | |
//----- (FFF03174) -------------------------------------------------------- | |
Result __fastcall KPerformanceCounterControlHelper::BindInterrupt(s32 coreId) | |
{ | |
return KInterruptManager::BindInterrupt(&g_interruptManager, &g_perfCounterControlHelper, 4u, coreId, 0, 0, 0); | |
} | |
//----- (FFF031B0) -------------------------------------------------------- | |
void __fastcall KCacheMaintenanceHelper::ThreadFunction(KCacheMaintenanceHelper *this) | |
{ | |
u32 startAddr; // r0 | |
u32 endAddr; // r1 | |
unsigned int v4; // r2 | |
unsigned int v5; // r0 | |
u32 v6; // r3 | |
unsigned int v7; // r1 | |
unsigned int v8; // r3 | |
bool v9; // cf | |
unsigned int v10; // r0 | |
u32 i; // r1 | |
unsigned int v12; // r0 | |
u32 j; // r1 | |
unsigned int v14; // r0 | |
u32 k; // r1 | |
KThread *thread; // r5 | |
unsigned __int8 *p_numClients; // r0 | |
unsigned __int8 v18; // r1 | |
KThread *next; // r5 | |
KThread *v20; // r2 | |
KThreadIntrusiveList *v21; // r3 | |
int schedulingMask; // r0 | |
bool v23; // zf | |
while ( 1 ) | |
{ | |
switch ( this->op ) | |
{ | |
case KCACHEMAINTOP_FLAG_BY_MVA: | |
startAddr = this->startAddr; | |
endAddr = this->endAddr; | |
v4 = startAddr & ~0x1Fu; | |
v5 = (startAddr + 31) & ~0x1Fu; | |
v6 = endAddr + 31; | |
v7 = endAddr & ~0x1Fu; | |
v8 = v6 & ~0x1Fu; | |
if ( v4 < v5 ) | |
__mcr(15, 0, v4, 7, 14, 1); | |
v9 = v5 >= v8; | |
if ( v5 < v8 ) | |
v9 = v7 >= v8; | |
if ( !v9 ) | |
__mcr(15, 0, v7, 7, 14, 1); | |
for ( ; v5 < v7; v5 += 32 ) | |
__mcr(15, 0, v5, 7, 6, 1); | |
goto LABEL_23; | |
case KCACHEMAINTOP_CLEAN_DCACHE_BY_MVA: | |
v10 = this->startAddr; | |
for ( i = this->endAddr; v10 < i; v10 += 32 ) | |
__mcr(15, 0, v10, 7, 10, 1); | |
goto LABEL_23; | |
case KCACHEMAINTOP_CLEANINV_DCACHE_BY_MVA: | |
v12 = this->startAddr; | |
for ( j = this->endAddr; v12 < j; v12 += 32 ) | |
__mcr(15, 0, v12, 7, 14, 1); | |
goto LABEL_23; | |
case KCACHEMAINTOP_INV_ICACHE_BY_MVA: | |
v14 = this->startAddr; | |
for ( k = this->endAddr; v14 < k; v14 += 32 ) | |
__mcr(15, 0, v14, 7, 5, 1); | |
goto LABEL_19; | |
case KCACHEMAINTOP_FLAG_ENTIRE: | |
__mcr(15, 0, 0, 7, 6, 0); | |
__mcr(15, 0, 0, 7, 10, 4); | |
break; | |
case KCACHEMAINTOP_CLEAN_ENTIRE_DCACHE: | |
__mcr(15, 0, 0, 7, 10, 0); | |
goto LABEL_23; | |
case KCACHEMAINTOP_CLEANINV_ENTIRE_DCACHE: | |
__mcr(15, 0, 0, 7, 14, 0); | |
LABEL_23: | |
__mcr(15, 0, 0, 7, 10, 4); | |
break; | |
case KCACHEMAINTOP_INV_ENTIRE_ICACHE: | |
__mcr(15, 0, 0, 7, 5, 0); | |
LABEL_19: | |
__mcr(15, 0, 0, 7, 5, 6); | |
__mcr(15, 0, 0, 7, 10, 4); | |
__mcr(15, 0, 0, 7, 5, 4); | |
break; | |
default: | |
break; | |
} | |
thread = current.clc.current.thread; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_PAUSED); | |
p_numClients = &this->numClients; | |
do | |
v18 = __ldrex(p_numClients); | |
while ( __strex(v18 - 1, p_numClients) ); | |
if ( v18 == 1 ) | |
{ | |
if ( this->firstClientThread ) | |
{ | |
KThread::SetSchedulingState(this->firstClientThread, KTHREADSCHEDSTAT_RUNNING); | |
this->firstClientThread = 0; | |
} | |
__mcr(15, 0, 0, 7, 10, 4); | |
this->op = KCACHEMAINTOP_NONE; | |
__mcr(15, 0, 0, 7, 10, 4); | |
if ( this->waitList.link.next ) | |
{ | |
do | |
{ | |
next = this->waitList.link.next; | |
if ( !next ) | |
break; | |
v20 = next->link.next; | |
v21 = v20 ? (KThreadIntrusiveList *)&v20->link : &this->waitList; | |
this->waitList.link.next = v20; | |
v21->link.prev = 0; | |
next->waiterList = 0; | |
KThread::SetSchedulingState(next, KTHREADSCHEDSTAT_RUNNING); | |
next->waiterList = 0; | |
schedulingMask = next->schedulingMask; | |
v23 = schedulingMask == KTHREADSCHEDSTAT_RUNNING; | |
if ( schedulingMask != KTHREADSCHEDSTAT_RUNNING ) | |
v23 = this->waitList.link.next == 0; | |
} | |
while ( !v23 ); | |
} | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
} | |
// FFF031D0: control flows out of bounds to FFF031D4 | |
//----- (FFF033CC) -------------------------------------------------------- | |
void __fastcall KPageTable::InvalidateEntireInstructionCacheLocal() | |
{ | |
__mcr(15, 0, 0, 7, 5, 0); | |
__mcr(15, 0, 0, 7, 5, 6); | |
__mcr(15, 0, 0, 7, 10, 4); | |
__mcr(15, 0, 0, 7, 5, 4); | |
} | |
//----- (FFF033E4) -------------------------------------------------------- | |
u32 __fastcall crc32(void *data, u32 size, u32 initialValue) | |
{ | |
unsigned int i; // r6 | |
unsigned int v4; // r3 | |
int v5; // r4 | |
unsigned int v6; // r12 | |
u8 *v7; // r0 | |
u8 v8; // t1 | |
u32 j; // r1 | |
int v10; // r4 | |
u8 v11; // t1 | |
u32 v12; // r2 | |
u32 lut[256]; // [sp+4h] [bp+0h] | |
for ( i = 0; i < 0x100; ++i ) | |
{ | |
v4 = i; | |
v5 = 4; | |
do | |
{ | |
if ( (v4 & 1) != 0 ) | |
v6 = (v4 >> 1) ^ 0xEDB88320; | |
else | |
v6 = v4 >> 1; | |
if ( (v6 & 1) != 0 ) | |
v4 = (v6 >> 1) ^ 0xEDB88320; | |
else | |
v4 = v6 >> 1; | |
--v5; | |
} | |
while ( v5 ); | |
lut[i] = v4; | |
} | |
if ( size ) | |
{ | |
v7 = (u8 *)data - 1; | |
if ( (size & 1) != 0 ) | |
{ | |
v8 = *++v7; | |
initialValue = lut[(unsigned __int8)(v8 ^ initialValue)] ^ (initialValue >> 8); | |
} | |
for ( j = size >> 1; j; initialValue = lut[(unsigned __int8)(v11 ^ v12)] ^ (v12 >> 8) ) | |
{ | |
--j; | |
v10 = (unsigned __int8)(v7[1] ^ initialValue); | |
v11 = v7[2]; | |
v7 += 2; | |
v12 = lut[v10] ^ (initialValue >> 8); | |
} | |
} | |
return ~initialValue; | |
} | |
// FFF033E4: using guessed type u32 anonymous_0[259]; | |
//----- (FFF034B4) -------------------------------------------------------- | |
u32 __fastcall InitialProcess::GetCxiSize(InitialProcess *this) | |
{ | |
Ncch *ncch; // r6 | |
s32 v2; // r7 | |
s32 v3; // r4 | |
ncch = this->ncch; | |
v2 = ncch->flags[6] + 9; | |
v3 = Ncch::ConvertSize(ncch->exeFsSize, 0, v2); | |
return Ncch::ConvertSize(ncch->exeFsOffset, 0, v2) + v3; | |
} | |
//----- (FFF034F0) -------------------------------------------------------- | |
void __fastcall AtomicBoolStore(AtomicBool *this, bool value) | |
{ | |
do | |
__ldrex((unsigned __int8 *)this); | |
while ( __strex(value, (unsigned __int8 *)this) ); | |
} | |
//----- (FFF03514) -------------------------------------------------------- | |
// positive sp value has been detected, the output may be wrong! | |
void __fastcall __noreturn DispatchKernelExceptionWithRegdump(int a1, int a2, int a3, int a4, int a5) | |
{ | |
int v5; // r4 | |
int v11; // [sp-10h] [bp-10h] | |
char v12; // [sp-9h] [bp-9h] BYREF | |
int v13[2]; // [sp-8h] [bp-8h] BYREF | |
_R2 = __get_CPSR(); | |
__asm | |
{ | |
CPS #0x13 | |
MSR CPSR_cxsf, R2 | |
} | |
if ( (int)(&v12 - ((unsigned int)&v12 & 0xFFFFF000)) >= 1024 ) | |
{ | |
__asm | |
{ | |
SRSDB SP!, #0x13 | |
CPS #0x13 | |
} | |
v11 = a4; | |
__asm | |
{ | |
MSR CPSR_cxsf, R2 | |
CPS #0x13 | |
} | |
DispatchExceptionWithRegdump(a4, v5, v13[0], v13[1], a5); | |
} | |
kernelpanic(); | |
} | |
// FFF03550: positive sp value 8 has been found | |
// FFF03554: variable 'v5' is possibly undefined | |
//----- (FFF03564) -------------------------------------------------------- | |
void __fastcall LzssDecompress(u8 *fileEnd) | |
{ | |
unsigned int v1; // r1 | |
u8 *v2; // r2 | |
u8 *v3; // r3 | |
u8 *v4; // r1 | |
char v5; // r5 | |
char v6; // t1 | |
int v7; // r6 | |
bool v8; // cc | |
u8 v9; // t1 | |
u8 *v10; // r3 | |
int v11; // r12 | |
int v12; // t1 | |
int v13; // t1 | |
unsigned int v14; // r7 | |
int v15; // r12 | |
if ( fileEnd ) | |
{ | |
v1 = *((_DWORD *)fileEnd - 2); | |
v2 = &fileEnd[*((_DWORD *)fileEnd - 1)]; | |
v3 = &fileEnd[-HIBYTE(v1)]; | |
v4 = &fileEnd[-(v1 & 0xFFFFFF)]; | |
while ( (int)v3 > (int)v4 ) | |
{ | |
v6 = *--v3; | |
v5 = v6; | |
v7 = 8; | |
while ( 1 ) | |
{ | |
v8 = v7-- < 1; | |
if ( v8 ) | |
break; | |
if ( (v5 & 0x80) != 0 ) | |
{ | |
v12 = *(v3 - 1); | |
v10 = v3 - 1; | |
v11 = v12; | |
v13 = *(v10 - 1); | |
v3 = v10 - 1; | |
v14 = ((v13 | (v11 << 8)) & 0xFFFF0FFF) + 2; | |
v15 = v11 + 32; | |
do | |
{ | |
*(v2 - 1) = v2[v14]; | |
--v2; | |
v8 = v15 < 16; | |
v15 -= 16; | |
} | |
while ( !v8 ); | |
} | |
else | |
{ | |
v9 = *--v3; | |
*--v2 = v9; | |
} | |
v5 *= 2; | |
if ( (int)v3 <= (int)v4 ) | |
return; | |
} | |
} | |
} | |
} | |
//----- (FFF035F8) -------------------------------------------------------- | |
Result __fastcall SvcAcceptSession(int a1, Handle a2) | |
{ | |
Handle outServerSessionHandle; // [sp+0h] [bp-8h] BYREF | |
return AcceptSession(&outServerSessionHandle, a2); | |
} | |
//----- (FFF03614) -------------------------------------------------------- | |
Result __fastcall SvcArbitrateAddress(Handle a1, u32 a2, ArbitrationType a3, s32 a4) | |
{ | |
s64 timeout; // r4 | |
return ArbitrateAddress(a1, a2, a3, a4, timeout); | |
} | |
// FFF03624: variable 'timeout' is possibly undefined | |
//----- (FFF03630) -------------------------------------------------------- | |
Result __fastcall SvcConnectToPort(int a1, const char *a2) | |
{ | |
Handle outClientSessionHandle; // [sp+0h] [bp-8h] BYREF | |
return ConnectToPort(&outClientSessionHandle, a2); | |
} | |
//----- (FFF0364C) -------------------------------------------------------- | |
Result __fastcall SvcControlMemory(u8 op, u32 a2, u32 a3, u32 a4) | |
{ | |
u32 perms; // r4 | |
u32 outAddr; // [sp+8h] [bp-8h] BYREF | |
return ControlMemory(&outAddr, a2, a3, a4, op, perms); | |
} | |
// FFF03660: variable 'perms' is possibly undefined | |
//----- (FFF03670) -------------------------------------------------------- | |
Result __fastcall SvcControlPerformanceCounter( | |
unsigned int a1, | |
PerformanceCounterOperation a2, | |
u32 a3, | |
unsigned int a4) | |
{ | |
s64 out; // [sp+8h] [bp-10h] BYREF | |
return ControlPerformanceCounter(&out, a2, a3, __PAIR64__(a4, a1)); | |
} | |
//----- (FFF03698) -------------------------------------------------------- | |
Result __fastcall SvcControlProcessMemory(Handle a1, u32 a2, u32 a3, u32 a4) | |
{ | |
u32 op; // r4 | |
u32 perms; // r5 | |
return ControlProcessMemory(a1, a2, a3, a4, op, perms); | |
} | |
// FFF036A8: variable 'op' is possibly undefined | |
// FFF036A8: variable 'perms' is possibly undefined | |
//----- (FFF036B4) -------------------------------------------------------- | |
Result SvcCreateAddressArbiter() | |
{ | |
Handle outArbiterHandle; // [sp+0h] [bp-8h] BYREF | |
return CreateAddressArbiter(&outArbiterHandle); | |
} | |
//----- (FFF036D0) -------------------------------------------------------- | |
Result __fastcall SvcCreateCodeSet(u32 dataPtr, CodeSetInfo *a2, u32 a3, u32 a4) | |
{ | |
Handle outHandle; // [sp+4h] [bp-Ch] BYREF | |
return CreateCodeSet(&outHandle, a2, a3, a4, dataPtr); | |
} | |
//----- (FFF036F0) -------------------------------------------------------- | |
Result __fastcall SvcCreateEvent(int a1, ResetType a2) | |
{ | |
Handle outEventHandle; // [sp+0h] [bp-8h] BYREF | |
return CreateEvent(&outEventHandle, a2); | |
} | |
//----- (FFF0370C) -------------------------------------------------------- | |
Result __fastcall SvcCreateMemoryBlock(u32 othersPerms, u32 a2, u32 a3, u32 a4) | |
{ | |
Handle outSharedMemHandle; // [sp+4h] [bp-Ch] BYREF | |
return CreateMemoryBlock(&outSharedMemHandle, a2, a3, a4, othersPerms); | |
} | |
//----- (FFF0372C) -------------------------------------------------------- | |
Result __fastcall SvcCreateMutex(int a1, BOOL a2) | |
{ | |
Handle outMutexHandle; // [sp+0h] [bp-8h] BYREF | |
return CreateMutex(&outMutexHandle, a2); | |
} | |
//----- (FFF03748) -------------------------------------------------------- | |
Result __fastcall SvcCreatePort(int a1, int a2, const char *a3, s32 a4) | |
{ | |
Handle outClientPortHandle; // [sp+0h] [bp-10h] BYREF | |
Handle outSessionPortHandle; // [sp+4h] [bp-Ch] BYREF | |
return CreatePort(&outSessionPortHandle, &outClientPortHandle, a3, a4); | |
} | |
//----- (FFF0376C) -------------------------------------------------------- | |
Result __fastcall SvcCreateProcess(int a1, Handle a2, u32 *a3, s32 a4) | |
{ | |
Handle outProcessHandle; // [sp+0h] [bp-8h] BYREF | |
return CreateProcess(&outProcessHandle, a2, a3, a4); | |
} | |
//----- (FFF03788) -------------------------------------------------------- | |
Result SvcCreateResourceLimit() | |
{ | |
Handle outReslimitHandle; // [sp+0h] [bp-8h] BYREF | |
return CreateResourceLimit(&outReslimitHandle); | |
} | |
//----- (FFF037A4) -------------------------------------------------------- | |
Result __fastcall SvcCreateSemaphore(int a1, s32 a2, s32 a3) | |
{ | |
Handle outSemaphoreHandle; // [sp+0h] [bp-8h] BYREF | |
return CreateSemaphore(&outSemaphoreHandle, a2, a3); | |
} | |
//----- (FFF037C0) -------------------------------------------------------- | |
Result SvcCreateSession() | |
{ | |
Handle outClientSessionHandle; // [sp+0h] [bp-10h] BYREF | |
Handle outServerSessionHandle; // [sp+4h] [bp-Ch] BYREF | |
return CreateSession(&outServerSessionHandle, &outClientSessionHandle); | |
} | |
//----- (FFF037E4) -------------------------------------------------------- | |
Result __fastcall SvcCreateSessionToPort(int a1, Handle a2) | |
{ | |
Handle outClientSessionHandle; // [sp+0h] [bp-8h] BYREF | |
return CreateSessionToPort(&outClientSessionHandle, a2); | |
} | |
//----- (FFF03800) -------------------------------------------------------- | |
Result __fastcall SvcCreateThread(s32 priority, u32 a2, u32 a3, u32 a4) | |
{ | |
s32 processorId; // r4 | |
Handle outThreadHandle; // [sp+8h] [bp-8h] BYREF | |
return CreateThread(&outThreadHandle, a2, a3, a4, priority, processorId); | |
} | |
// FFF03814: variable 'processorId' is possibly undefined | |
//----- (FFF03824) -------------------------------------------------------- | |
Result __fastcall SvcCreateTimer(int a1, ResetType a2) | |
{ | |
Handle outTimerHandle; // [sp+0h] [bp-8h] BYREF | |
return CreateTimer(&outTimerHandle, a2); | |
} | |
//----- (FFF03840) -------------------------------------------------------- | |
Result __fastcall SvcDebugActiveProcess(int a1, u32 a2) | |
{ | |
Handle outHandle; // [sp+0h] [bp-8h] BYREF | |
return DebugActiveProcess(&outHandle, a2); | |
} | |
//----- (FFF0385C) -------------------------------------------------------- | |
Result __fastcall SvcDuplicateHandle(int a1, Handle a2) | |
{ | |
Handle outHandle; // [sp+0h] [bp-8h] BYREF | |
return DuplicateHandle(&outHandle, a2); | |
} | |
//----- (FFF03878) -------------------------------------------------------- | |
Result __fastcall SvcGetDebugThreadParam(DebugThreadParameter param, int a2, Handle a3, u32 a4) | |
{ | |
s32 out2; // [sp+4h] [bp-14h] BYREF | |
s64 out1; // [sp+8h] [bp-10h] BYREF | |
return GetDebugThreadParam(&out1, &out2, a3, a4, param); | |
} | |
//----- (FFF038A4) -------------------------------------------------------- | |
Result __fastcall SvcGetDmaState(int a1, Handle a2) | |
{ | |
DmaState outDmaState[4]; // [sp+0h] [bp-8h] BYREF | |
return GetDmaState(outDmaState, a2); | |
} | |
//----- (FFF038C0) -------------------------------------------------------- | |
Result __fastcall SvcGetHandleInfo(int a1, Handle a2, s32 a3) | |
{ | |
s64 out; // [sp+0h] [bp-10h] BYREF | |
return GetHandleInfo(&out, a2, a3); | |
} | |
//----- (FFF038E0) -------------------------------------------------------- | |
Result __fastcall SvcGetProcessId(int a1, Handle a2) | |
{ | |
u32 outPid; // [sp+0h] [bp-8h] BYREF | |
return GetProcessId(&outPid, a2); | |
} | |
//----- (FFF038FC) -------------------------------------------------------- | |
Result __fastcall SvcGetProcessIdOfThread(int a1, Handle a2) | |
{ | |
u32 outPid; // [sp+0h] [bp-8h] BYREF | |
return GetProcessIdOfThread(&outPid, a2); | |
} | |
//----- (FFF03918) -------------------------------------------------------- | |
Result __fastcall SvcGetProcessIdealProcessor(int a1, Handle a2) | |
{ | |
s32 outIdealProcessor; // [sp+0h] [bp-8h] BYREF | |
return GetProcessIdealProcessor(&outIdealProcessor, a2); | |
} | |
//----- (FFF03934) -------------------------------------------------------- | |
Result __fastcall SvcGetProcessInfo(int a1, Handle a2, s32 a3) | |
{ | |
s64 outValue; // [sp+0h] [bp-10h] BYREF | |
return GetProcessInfo(&outValue, a2, a3); | |
} | |
//----- (FFF03954) -------------------------------------------------------- | |
Result __fastcall SvcGetProcessList(int a1, u32 *a2, s32 a3) | |
{ | |
s32 outNumProcesses; // [sp+0h] [bp-8h] BYREF | |
return GetProcessList(&outNumProcesses, a2, a3); | |
} | |
//----- (FFF03970) -------------------------------------------------------- | |
Result __fastcall SvcGetResourceLimit(int a1, Handle a2) | |
{ | |
Handle outReslimit; // [sp+0h] [bp-8h] BYREF | |
return GetResourceLimit(&outReslimit, a2); | |
} | |
//----- (FFF0398C) -------------------------------------------------------- | |
Result __fastcall SvcGetSystemInfo(int a1, s32 a2, s32 a3) | |
{ | |
s64 out; // [sp+0h] [bp-10h] BYREF | |
return GetSystemInfo(&out, a2, a3); | |
} | |
//----- (FFF039AC) -------------------------------------------------------- | |
Result __fastcall SvcGetThreadId(int a1, Handle a2) | |
{ | |
u32 threadId; // [sp+0h] [bp-8h] BYREF | |
return GetThreadId(&threadId, a2); | |
} | |
//----- (FFF039C8) -------------------------------------------------------- | |
Result __fastcall SvcGetThreadIdealProcessor(int a1, Handle a2) | |
{ | |
s32 outIdealProcessor; // [sp+0h] [bp-8h] BYREF | |
return GetThreadIdealProcessor(&outIdealProcessor, a2); | |
} | |
//----- (FFF039E4) -------------------------------------------------------- | |
Result __fastcall SvcGetThreadInfo(int a1, Handle a2, s32 a3) | |
{ | |
s64 outValue; // [sp+0h] [bp-10h] BYREF | |
return GetThreadInfo(&outValue, a2, a3); | |
} | |
//----- (FFF03A04) -------------------------------------------------------- | |
Result __fastcall SvcGetThreadList(int a1, u32 *a2, s32 a3, Handle a4) | |
{ | |
s32 outNumThreads; // [sp+0h] [bp-8h] BYREF | |
return GetThreadList(&outNumThreads, a2, a3, a4); | |
} | |
//----- (FFF03A20) -------------------------------------------------------- | |
Result __fastcall SvcGetThreadPriority(int a1, Handle a2) | |
{ | |
s32 outPriority; // [sp+0h] [bp-8h] BYREF | |
return GetThreadPriority(&outPriority, a2); | |
} | |
//----- (FFF03A3C) -------------------------------------------------------- | |
Result Svc0x74_CodeSetRelated_stubbed() | |
{ | |
Handle codesetHandleMaybe; // [sp+0h] [bp-8h] BYREF | |
return Svc0x74Impl_CodeSetRelated_Stubbed(&codesetHandleMaybe); | |
} | |
//----- (FFF03A58) -------------------------------------------------------- | |
Result __fastcall SvcOpenProcess(int a1, u32 a2) | |
{ | |
Handle outProcessHandle; // [sp+0h] [bp-8h] BYREF | |
return OpenProcess(&outProcessHandle, a2); | |
} | |
//----- (FFF03A74) -------------------------------------------------------- | |
Result __fastcall SvcOpenThread(int a1, Handle a2, u32 a3) | |
{ | |
Handle outThreadHandle; // [sp+0h] [bp-8h] BYREF | |
return OpenThread(&outThreadHandle, a2, a3); | |
} | |
//----- (FFF03A90) -------------------------------------------------------- | |
Result __fastcall SvcQueryDebugProcessMemory(int a1, int a2, Handle a3, u32 a4) | |
{ | |
u32 outPgInfo; // [sp+0h] [bp-18h] BYREF | |
MemoryInfo outMemInfo; // [sp+4h] [bp-14h] BYREF | |
return QueryDebugProcessMemory(&outMemInfo, &outPgInfo, a3, a4); | |
} | |
//----- (FFF03AC0) -------------------------------------------------------- | |
Result __fastcall SvcQueryMemory(int a1, int a2, u32 a3) | |
{ | |
u32 outPgInfo; // [sp+0h] [bp-18h] BYREF | |
MemoryInfo outMemInfo; // [sp+4h] [bp-14h] BYREF | |
return QueryMemory(&outMemInfo, &outPgInfo, a3); | |
} | |
//----- (FFF03AF0) -------------------------------------------------------- | |
Result __fastcall SvcQueryProcessMemory(int a1, int a2, Handle a3, u32 a4) | |
{ | |
u32 outPgInfo; // [sp+0h] [bp-18h] BYREF | |
MemoryInfo outMemInfo; // [sp+4h] [bp-14h] BYREF | |
return QueryProcessMemory(&outMemInfo, &outPgInfo, a3, a4); | |
} | |
//----- (FFF03B20) -------------------------------------------------------- | |
Result __fastcall SvcReleaseSemaphore(int a1, Handle a2, s32 a3) | |
{ | |
s32 outCount; // [sp+0h] [bp-8h] BYREF | |
return ReleaseSemaphore(&outCount, a2, a3); | |
} | |
//----- (FFF03B3C) -------------------------------------------------------- | |
Result __fastcall SvcReplyAndReceive(int a1, Handle *a2, s32 a3, Handle a4) | |
{ | |
s32 outIdx; // [sp+0h] [bp-8h] BYREF | |
return ReplyAndReceive(&outIdx, a2, a3, a4); | |
} | |
//----- (FFF03B58) -------------------------------------------------------- | |
Result __fastcall SvcReplyAndReceive1(int a1, Handle *a2, s32 a3, Handle a4) | |
{ | |
s32 outIdx; // [sp+0h] [bp-8h] BYREF | |
return ReplyAndReceive1(&outIdx, a2, a3, a4); | |
} | |
//----- (FFF03B74) -------------------------------------------------------- | |
Result __fastcall SvcReplyAndReceive2(int a1, Handle *a2, s32 a3, Handle a4) | |
{ | |
s32 outIdx; // [sp+0h] [bp-8h] BYREF | |
return ReplyAndReceive2(&outIdx, a2, a3, a4); | |
} | |
//----- (FFF03B90) -------------------------------------------------------- | |
Result __fastcall SvcReplyAndReceive3(int a1, Handle *a2, s32 a3, Handle a4) | |
{ | |
s32 outIdx; // [sp+0h] [bp-8h] BYREF | |
return ReplyAndReceive3(&outIdx, a2, a3, a4); | |
} | |
//----- (FFF03BAC) -------------------------------------------------------- | |
Result __fastcall SvcReplyAndReceive4(int a1, Handle *a2, s32 a3, Handle a4) | |
{ | |
s32 outIdx; // [sp+0h] [bp-8h] BYREF | |
return ReplyAndReceive4(&outIdx, a2, a3, a4); | |
} | |
//----- (FFF03BC8) -------------------------------------------------------- | |
Result __fastcall SvcRestartDma(Handle a1, u32 a2, u32 a3, u32 a4) | |
{ | |
DmaRestartFlags restartFlags; // r4 | |
return RestartDma(a1, a2, a3, a4, restartFlags); | |
} | |
// FFF03BD4: variable 'restartFlags' is possibly undefined | |
//----- (FFF03BE0) -------------------------------------------------------- | |
Result __fastcall SvcRun(Handle a1, s32 a2, u32 a3, s32 a4) | |
{ | |
u16 *v4; // r4 | |
u16 *v5; // r5 | |
StartupInfo info; // [sp+0h] [bp-18h] BYREF | |
info.mainThreadPriority = a2; | |
info.stackSize = a3; | |
info.argc = a4; | |
info.argv = v4; | |
info.envp = v5; | |
return Run(a1, &info); | |
} | |
// FFF03BF4: variable 'v4' is possibly undefined | |
// FFF03BF8: variable 'v5' is possibly undefined | |
//----- (FFF03C0C) -------------------------------------------------------- | |
Result __fastcall SvcSetTimer(Handle a1, unsigned int a2, s64 a3) | |
{ | |
unsigned int v3; // r4 | |
return SetTimer(a1, a3, __SPAIR64__(v3, a2)); | |
} | |
// FFF03C1C: variable 'v3' is possibly undefined | |
//----- (FFF03C28) -------------------------------------------------------- | |
Result __fastcall SvcSignalAndWait(bool waitAll, Handle a2, Handle *a3, s32 a4) | |
{ | |
int v4; // r5 | |
s64 timeout; // [sp+8h] [bp-10h] BYREF | |
LODWORD(timeout) = v4; | |
return SignalAndWait((s32 *)&timeout + 1, a2, a3, a4, waitAll, timeout); | |
} | |
// FFF03C34: variable 'v4' is possibly undefined | |
//----- (FFF03C50) -------------------------------------------------------- | |
Result __fastcall SvcStartInterProcessDma(u32 srcAddr, Handle a2, u32 a3, Handle a4) | |
{ | |
u32 size; // r4 | |
const DmaConfig *config; // r5 | |
Handle outDmaHandle; // [sp+Ch] [bp-Ch] BYREF | |
return StartInterProcessDma(&outDmaHandle, a2, a3, a4, srcAddr, size, config); | |
} | |
// FFF03C68: variable 'size' is possibly undefined | |
// FFF03C68: variable 'config' is possibly undefined | |
//----- (FFF03C78) -------------------------------------------------------- | |
Result __fastcall SvcWaitSynchronizationN(unsigned int a1, Handle *a2, s32 a3, bool a4) | |
{ | |
unsigned int v4; // r4 | |
s32 outIdx; // [sp+8h] [bp-8h] BYREF | |
return WaitSynchronizationN(&outIdx, a2, a3, a4, __SPAIR64__(v4, a1)); | |
} | |
// FFF03C8C: variable 'v4' is possibly undefined | |
//----- (FFF03C9C) -------------------------------------------------------- | |
void __fastcall InitialProcess::AllocateSegment( | |
InitialProcess *this, | |
void **loadAddr, | |
CodeSegmentInfo *sectionBounds, | |
ExHeader_CodeSectionInfo *codeSectionInfo) | |
{ | |
u32 v5; // r5 | |
void *allocd; // r7 | |
unsigned int v7; // r2 | |
bool v8; // zf | |
unsigned int v9; // r3 | |
sectionBounds->addr = codeSectionInfo->address; | |
sectionBounds->size = codeSectionInfo->nbPages; | |
v5 = (codeSectionInfo->size + 4095) >> 12; | |
allocd = (void *)KMemoryManager::AllocateContiguous(&g_memoryManager, v5, 1u, MEMOP_REGION_BASE); | |
v7 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v8 = v7 == 0; | |
if ( v7 ) | |
v9 = __strex(v7, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v9 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v7 ) | |
v8 = v9 == 0; | |
if ( !v8 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)allocd, v5); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
*loadAddr = allocd; | |
} | |
//----- (FFF03D48) -------------------------------------------------------- | |
void __fastcall KPageManager::Intialize(KPageManager *this, u32 numPages) | |
{ | |
signed __int32 numRefcountPages; // r8 | |
KMemoryManager *p_mm; // r7 | |
unsigned int *p_mutex; // r0 | |
KLightMutex *v7; // r4 | |
unsigned int v8; // r2 | |
bool v9; // zf | |
unsigned int v10; // r3 | |
unsigned int *kernMemUsage; // r0 | |
unsigned int v12; // r2 | |
u32 *refcounts; // r7 | |
u32 v14; // r0 | |
int v15; // r1 | |
int v16; // r1 | |
KMemoryManager *mm; // r4 | |
KLightMutex *v18; // r5 | |
unsigned int v19; // r2 | |
bool v20; // zf | |
unsigned int v21; // r3 | |
unsigned int refcountPagePosition; // r0 | |
unsigned int v23; // r2 | |
char v24; // cc | |
int v25; // r2 | |
int v26; // r1 | |
int v27; // r3 | |
unsigned int v28; // r7 | |
int v29; // r3 | |
unsigned int v30; // r8 | |
numRefcountPages = ((4 * numPages - 1) >> 12) + 1;// one 32-bit word per page | |
p_mm = this->mm; | |
p_mutex = (unsigned int *)&p_mm->pgMgr.mutex; | |
v7 = &p_mm->pgMgr.mutex; | |
v8 = __ldrex((unsigned int *)&p_mm->pgMgr.mutex); | |
v9 = v8 == 0; | |
if ( v8 ) | |
v10 = __strex(v8, p_mutex); | |
else | |
v10 = __strex((unsigned int)current.clc.current.thread, p_mutex); | |
if ( !v8 ) | |
v9 = v10 == 0; | |
if ( !v9 ) | |
KLightMutex::LockImpl((KLightMutex *)p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
kernMemUsage = &p_mm->pgMgr.kernelMemoryUsage; | |
do | |
v12 = __ldrex(kernMemUsage); | |
while ( __strex(v12 + (numRefcountPages << 12), kernMemUsage) ); | |
refcounts = (u32 *)KPageHeap::AllocateContiguous(&p_mm->baseHeap, numRefcountPages, 0); | |
__mcr(15, 0, 0, 7, 10, 5); | |
v7->lockingThread = 0; | |
if ( v7->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v7); | |
if ( refcounts ) | |
{ | |
this->pageRefcounts = refcounts; | |
if ( numPages ) | |
{ | |
v14 = numPages & 1; | |
v15 = 0; | |
if ( v14 == 1 ) | |
{ | |
v15 = 1; | |
*refcounts = 0; | |
} | |
for ( ; v14 < numPages; v15 = v16 + 1 ) | |
{ | |
v14 += 2; | |
this->pageRefcounts[v15] = 0; | |
v16 = v15 + 1; | |
this->pageRefcounts[v16] = 0; | |
} | |
} | |
mm = this->mm; | |
v18 = &this->mm->pgMgr.mutex; | |
v19 = __ldrex((unsigned int *)v18); | |
v20 = v19 == 0; | |
if ( v19 ) | |
v21 = __strex(v19, (unsigned int *)v18); | |
else | |
v21 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)v18); | |
if ( !v19 ) | |
v20 = v21 == 0; | |
if ( !v20 ) | |
KLightMutex::LockImpl(v18); | |
__mcr(15, 0, 0, 7, 10, 5); | |
refcountPagePosition = ((unsigned int)refcounts - mm->pgMgr.memoryStartAddr) >> 12; | |
v23 = refcountPagePosition + numRefcountPages; | |
v24 = (refcountPagePosition + numRefcountPages != 0x7FFFFFFF) & __CFADD__( | |
refcountPagePosition + numRefcountPages, | |
-2147483647); | |
if ( refcountPagePosition + numRefcountPages <= 0x7FFFFFFF ) | |
v24 = (refcountPagePosition != 0x7FFFFFFF) & __CFADD__(refcountPagePosition, -2147483647); | |
if ( v24 ) | |
{ | |
for ( ; refcountPagePosition < v23; ++refcountPagePosition ) | |
++mm->pgMgr.pageRefcounts[refcountPagePosition]; | |
} | |
else | |
{ | |
v25 = numRefcountPages; | |
if ( numRefcountPages > 0 ) | |
{ | |
v26 = numRefcountPages & 1; | |
v27 = 0; | |
if ( v26 == 1 ) | |
{ | |
v27 = 1; | |
++mm->pgMgr.pageRefcounts[refcountPagePosition]; | |
} | |
if ( numRefcountPages > v26 ) | |
{ | |
do | |
{ | |
v28 = refcountPagePosition + v27; | |
v29 = v27 + 1; | |
v30 = refcountPagePosition + v29; | |
v26 += 2; | |
++mm->pgMgr.pageRefcounts[v28]; | |
v27 = v29 + 1; | |
++mm->pgMgr.pageRefcounts[v30]; | |
} | |
while ( v25 > v26 ); | |
} | |
} | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
v18->lockingThread = 0; | |
if ( v18->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v18); | |
} | |
} | |
// FFF03DD0: conditional instruction was optimized away because r0.4==300 | |
// FFF03DD8: conditional instruction was optimized away because r0.4==300 | |
//----- (FFF04004) -------------------------------------------------------- | |
KThreadIntrusiveList *__fastcall KThreadIntrusiveList::KThreadIntrusiveList(KThreadIntrusiveList *this) | |
{ | |
this->link.prev = 0; | |
this->link.next = 0; | |
return this; | |
} | |
//----- (FFF04014) -------------------------------------------------------- | |
void __fastcall KAffinityMask::Normalize(KAffinityMask *dstAffMask, KAffinityMask *this, u8 numCores) | |
{ | |
*dstAffMask = *this & ~(-1 << numCores); | |
} | |
//----- (FFF04028) -------------------------------------------------------- | |
void PostSvcDpcHandler(void) | |
{ | |
KThread::HandleDpc(current.clc.current.thread); | |
} | |
//----- (FFF04038) -------------------------------------------------------- | |
Result __fastcall SvcStopDma(Handle dmaObjectHandle) | |
{ | |
KDmaObject *v1; // r0 | |
KDmaObject *v2; // r4 | |
KDmaObject *dmaObj; // r5 | |
u8 typeId; // r8 | |
int channelId; // r0 | |
KTypeObj v7; // [sp+0h] [bp-28h] BYREF | |
KTypeObj v8; // [sp+8h] [bp-20h] BYREF | |
v1 = (KDmaObject *)KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, dmaObjectHandle); | |
v2 = v1; | |
if ( !v1 ) | |
return 0xD8E007F7; | |
dmaObj = v1; | |
v1->GetTypeObj(&v7, v1); | |
typeId = v7.typeId; | |
dmaObj->GetTypeObj(&v8, dmaObj); | |
if ( (typeId | 0x59) != v8.typeId ) | |
{ | |
dmaObj = 0; | |
v2->DecrementRefcount(v2); | |
} | |
if ( !dmaObj ) | |
return 0xD8E007F7; | |
dmaObj->DecrementRefcount(dmaObj); // uaf | |
channelId = dmaObj->channelId; | |
if ( channelId >= 0 ) | |
KDmaChannel::AbortTransfer(&g_dmaChannels[channelId]); | |
return 0; | |
} | |
//----- (FFF04128) -------------------------------------------------------- | |
Result __fastcall SvcClearEvent(Handle eventHandle) | |
{ | |
KAutoObject *v1; // r0 | |
KAutoObject *v2; // r4 | |
u8 typeId; // r7 | |
int v4; // r1 | |
KEvent *v5; // r5 | |
KEvent *v6; // r4 | |
Result v7; // r5 | |
KTypeObj v9; // [sp+0h] [bp-28h] BYREF | |
KTypeObj v10; // [sp+8h] [bp-20h] BYREF | |
v1 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, eventHandle); | |
v2 = v1; | |
if ( !v1 ) | |
return 0xD8E007F7; | |
v1->GetTypeObj(&v9, v1); | |
typeId = v9.typeId; | |
v2->GetTypeObj(&v10, v2); | |
v4 = typeId | 0x1F; | |
v5 = v4 == v10.typeId ? (KEvent *)v2 : 0; | |
if ( v4 != v10.typeId ) | |
v2->DecrementRefcount(v2); | |
if ( !v5 ) | |
return 0xD8E007F7; | |
v6 = v5; | |
v7 = KEvent::Clear(v5); | |
v6->DecrementRefcount(v6); | |
return v7; | |
} | |
//----- (FFF04200) -------------------------------------------------------- | |
Result __fastcall SvcClearTimer(Handle timerHandle) | |
{ | |
KAutoObject *v1; // r0 | |
KAutoObject *v2; // r4 | |
u8 typeId; // r7 | |
int v4; // r1 | |
KTimer *v5; // r5 | |
KTimer *v6; // r4 | |
Result v7; // r5 | |
KTypeObj v9; // [sp+0h] [bp-28h] BYREF | |
KTypeObj v10; // [sp+8h] [bp-20h] BYREF | |
v1 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, timerHandle); | |
v2 = v1; | |
if ( !v1 ) | |
return 0xD8E007F7; | |
v1->GetTypeObj(&v9, v1); | |
typeId = v9.typeId; | |
v2->GetTypeObj(&v10, v2); | |
v4 = typeId | 0x35; | |
v5 = v4 == v10.typeId ? (KTimer *)v2 : 0; | |
if ( v4 != v10.typeId ) | |
v2->DecrementRefcount(v2); | |
if ( !v5 ) | |
return 0xD8E007F7; | |
v6 = v5; | |
v7 = KTimer::Clear(v5); | |
v6->DecrementRefcount(v6); | |
return v7; | |
} | |
//----- (FFF042D8) -------------------------------------------------------- | |
void __noreturn SvcExitThread(void) | |
{ | |
KThread::Exit(current.clc.current.thread); | |
} | |
//----- (FFF042F4) -------------------------------------------------------- | |
Result __fastcall SvcCancelTimer(Handle timerHandle) | |
{ | |
KAutoObject *v1; // r0 | |
KAutoObject *v2; // r4 | |
u8 typeId; // r7 | |
int v4; // r1 | |
KTimer *v5; // r5 | |
KTimer *v6; // r4 | |
Result v7; // r5 | |
KTypeObj v9; // [sp+0h] [bp-28h] BYREF | |
KTypeObj v10; // [sp+8h] [bp-20h] BYREF | |
v1 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, timerHandle); | |
v2 = v1; | |
if ( !v1 ) | |
return 0xD8E007F7; | |
v1->GetTypeObj(&v9, v1); | |
typeId = v9.typeId; | |
v2->GetTypeObj(&v10, v2); | |
v4 = typeId | 0x35; | |
v5 = v4 == v10.typeId ? (KTimer *)v2 : 0; | |
if ( v4 != v10.typeId ) | |
v2->DecrementRefcount(v2); | |
if ( !v5 ) | |
return 0xD8E007F7; | |
v6 = v5; | |
v7 = KTimer::Cancel(v5); | |
v6->DecrementRefcount(v6); | |
return v7; | |
} | |
//----- (FFF043CC) -------------------------------------------------------- | |
Result __fastcall SvcCloseHandle(Handle handle) | |
{ | |
if ( KHandleTable::CloseHandle(¤t.clc.current.process->handleTable, handle) ) | |
return 0; | |
else | |
return 0xD8E007F7; | |
} | |
//----- (FFF043FC) -------------------------------------------------------- | |
void __noreturn SvcExitProcess(void) | |
{ | |
KProcess::TerminateCurrentProcess(current.clc.current.process); | |
kernelpanic(); | |
} | |
//----- (FFF04418) -------------------------------------------------------- | |
Result __fastcall SvcSignalEvent(Handle eventHandle) | |
{ | |
KAutoObject *v1; // r0 | |
KAutoObject *v2; // r4 | |
u8 typeId; // r7 | |
int v4; // r1 | |
KEvent *v5; // r5 | |
KEvent *v6; // r4 | |
Result v7; // r5 | |
KTypeObj v9; // [sp+0h] [bp-28h] BYREF | |
KTypeObj v10; // [sp+8h] [bp-20h] BYREF | |
v1 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, eventHandle); | |
v2 = v1; | |
if ( !v1 ) | |
return 0xD8E007F7; | |
v1->GetTypeObj(&v9, v1); | |
typeId = v9.typeId; | |
v2->GetTypeObj(&v10, v2); | |
v4 = typeId | 0x1F; | |
v5 = v4 == v10.typeId ? (KEvent *)v2 : 0; | |
if ( v4 != v10.typeId ) | |
v2->DecrementRefcount(v2); | |
if ( !v5 ) | |
return 0xD8E007F7; | |
v6 = v5; | |
v7 = KEvent::Signal(v5); | |
v6->DecrementRefcount(v6); | |
return v7; | |
} | |
//----- (FFF044F0) -------------------------------------------------------- | |
void __fastcall SvcSleepThread(s64 timeout) | |
{ | |
if ( ((((unsigned __int64)-timeout >> 32) & 0x80000000) != 0LL) != __OFSUB__( | |
0, | |
HIDWORD(timeout), | |
(_DWORD)timeout == 0) ) | |
{ | |
KThread::Sleep(current.clc.current.thread, timeout); | |
} | |
else if ( !timeout ) | |
{ | |
KScheduler::YieldCurrentThread(current.clc.current.scheduler); | |
} | |
} | |
//----- (FFF04534) -------------------------------------------------------- | |
Result __fastcall SvcReleaseMutex(Handle mutexHandle) | |
{ | |
KAutoObject *v1; // r0 | |
KAutoObject *v2; // r4 | |
u8 typeId; // r7 | |
int v4; // r1 | |
KMutex *v5; // r5 | |
KMutex *v6; // r4 | |
Result v7; // r5 | |
KTypeObj v9; // [sp+0h] [bp-28h] BYREF | |
KTypeObj v10; // [sp+8h] [bp-20h] BYREF | |
v1 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, mutexHandle); | |
v2 = v1; | |
if ( !v1 ) | |
return 0xD8E007F7; | |
v1->GetTypeObj(&v9, v1); | |
typeId = v9.typeId; | |
v2->GetTypeObj(&v10, v2); | |
v4 = typeId | 0x39; | |
v5 = v4 == v10.typeId ? (KMutex *)v2 : 0; | |
if ( v4 != v10.typeId ) | |
v2->DecrementRefcount(v2); | |
if ( !v5 ) | |
return 0xD8E007F7; | |
v6 = v5; | |
v7 = KMutex::Unlock(v5, current.clc.current.thread); | |
v6->DecrementRefcount(v6); | |
return v7; | |
} | |
//----- (FFF04618) -------------------------------------------------------- | |
Result __fastcall SvcBindInterrupt(s32 irqId, Handle interruptEvent, s32 priority, BOOL levelSensitive) | |
{ | |
KProcess *process; // r10 | |
KInterruptEvent *v8; // r4 | |
int v9; // r11 | |
int v10; // r1 | |
bool v11; // zf | |
Result v13; // r5 | |
Result v14; // r0 | |
u8 fiq_mask; // r1 | |
KTypeObj result; // [sp+0h] [bp-68h] BYREF | |
KTypeObj v17; // [sp+10h] [bp-58h] | |
KTypeObj v18; // [sp+28h] [bp-40h] BYREF | |
KTypeObj v19; // [sp+30h] [bp-38h] | |
KTypeObj v20; // [sp+38h] [bp-30h] | |
process = current.clc.current.process; | |
v8 = KHandleTable::ConvertToInterruptEvent(¤t.clc.current.process->handleTable, interruptEvent); | |
if ( !v8 ) | |
return *MakeResultCode((Result *)&result.typeId, 0xFBu, 7u, 1u, 0x3F7u); | |
v9 = __mrc(15, 0, 0, 0, 5) & 3; | |
v17.typeId = 31; | |
v17.name = "KEvent"; | |
v19.name = "KEvent"; // "KEvent" | |
*(_DWORD *)&v19.typeId = *(_DWORD *)&v17.typeId; | |
v8->GetTypeObj(&v18, v8); | |
v17 = v18; | |
v8->GetTypeObj(&result, v8); | |
v20 = result; | |
v10 = v19.typeId | v17.typeId; | |
v11 = v10 == result.typeId; | |
if ( v10 == result.typeId ) | |
BYTE1(v8[1].KSynchronizationObject::KAutoObject::__vftable) = levelSensitive;// if KEvent, set manual clear=true to iff level-sensitive | |
else | |
v11 = !levelSensitive; | |
if ( !v11 ) | |
goto LABEL_15; | |
if ( irqId == 15 ) | |
{ | |
if ( !g_systemControl.targetSystem.isDevUnit )// | |
// UnbindInterrupt has a double-free issue in this path, | |
// so Nintendo just made it inaccessible on retail. | |
{ | |
LABEL_15: | |
v8->DecrementRefcount(v8); | |
return 0xD8E007EE; | |
} | |
if ( KFiqState::CompareExchangeStrong(&g_fiqState, KFIQSTATE_UNBOUND, KFIQSTATE_BOUND) ) | |
{ | |
v13 = 0xD8A007F0; | |
} | |
else if ( g_fiqHelper.interruptEvent ) | |
{ | |
KFiqState::Set(&g_fiqState, KFIQSTATE_UNBOUND);// lol yikes | |
// it leaks | |
v13 = 0xD8A007FC; | |
} | |
else | |
{ | |
g_fiqHelper.interruptEvent = v8; | |
g_fiqHelper.manualClear = levelSensitive; | |
g_fiqHelper.active = 0; | |
KAutoObject::IncrementRefcount(v8); | |
v8->irqId = 15; | |
v14 = KInterruptManager::BindInterrupt(&g_interruptManager, &g_fiqHelper.s, 0xFu, v9, priority, 0, 0); | |
v13 = v14; | |
if ( v14 >= 0 ) | |
{ | |
fiq_mask = CONFIG11.fiq_mask; | |
CONFIG11.fiq_mask = fiq_mask & ~2; | |
} | |
else | |
{ | |
v8->irqId = -1; | |
v8->DecrementRefcount(v8); | |
g_fiqHelper.interruptEvent = 0; | |
KFiqState::Set(&g_fiqState, KFIQSTATE_UNBOUND); | |
} | |
} | |
} | |
else | |
{ | |
v13 = KProcess::BindUserInterruptEvent(process, v8, irqId, v9, priority, levelSensitive); | |
} | |
v8->DecrementRefcount(v8); | |
return v13; | |
} | |
//----- (FFF0485C) -------------------------------------------------------- | |
s64 SvcGetSystemTick(void) | |
{ | |
return KHardwareTimer::GetSystemTick(&g_hardwareTimer); | |
} | |
//----- (FFF04868) -------------------------------------------------------- | |
int __fastcall SvcSetWifiEnabled(bool a1) | |
{ | |
SetWifiEnabled(a1); | |
return 0; | |
} | |
//----- (FFF04878) -------------------------------------------------------- | |
Result __fastcall SvcMapMemoryBlock(Handle sharedMemHandle, u32 addr, u32 myPerms, u32 othersPerms) | |
{ | |
Result result; // r0 | |
bool v9; // zf | |
Result v10; // r1 | |
bool v11; // zf | |
bool v12; // zf | |
KProcess *volatile process; // r8 | |
KAutoObject *v14; // r0 | |
KSharedMemory *v15; // r4 | |
KSharedMemory *v16; // r9 | |
u8 typeId; // r11 | |
Result v18; // r5 | |
KTypeObj v19; // [sp+0h] [bp-38h] BYREF | |
KTypeObj v20; // [sp+8h] [bp-30h] BYREF | |
result = addr << 20; | |
if ( addr << 20 ) | |
result = 0xE0E01BF1; // check if the addr is aligned (size not checked?) | |
if ( result >= 0 ) | |
{ | |
result = 0xE0E01BEE; | |
if ( !myPerms ) | |
goto LABEL_10; | |
v9 = myPerms == KMEMPERM_R; | |
if ( myPerms != KMEMPERM_R ) | |
v9 = myPerms == KMEMPERM_W; | |
if ( v9 || myPerms == KMEMPERM_RW ) | |
LABEL_10: | |
v10 = 0; | |
else | |
v10 = 0xE0E01BEE; | |
if ( v10 < 0 ) | |
return v10; | |
if ( othersPerms != KMEMPERM_W ) | |
{ | |
if ( (int)othersPerms > KMEMPERM_W ) | |
{ | |
v12 = othersPerms == KMEMPERM_RW; | |
if ( othersPerms != KMEMPERM_RW ) | |
v12 = othersPerms == MEMPERM_DONTCARE; | |
if ( !v12 ) | |
goto LABEL_25; | |
} | |
else | |
{ | |
v11 = othersPerms == KMEMPERM_NONE; | |
if ( othersPerms ) | |
v11 = othersPerms == KMEMPERM_R; | |
if ( !v11 ) | |
goto LABEL_25; | |
} | |
} | |
result = 0; | |
LABEL_25: | |
if ( result >= 0 ) | |
{ | |
if ( !addr || (addr < 0x8000000 || addr >= 0x14000000 ? (result = 0xE0E01BF5) : (result = 0), result >= 0) )// check if in heap or 0x10000000..0x14000000 range | |
{ | |
process = current.clc.current.process; | |
v14 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, sharedMemHandle); | |
v15 = (KSharedMemory *)v14; | |
v16 = 0; | |
if ( !v14 ) | |
return 0xD9001BF7; | |
v14->GetTypeObj(&v19, v14); | |
typeId = v19.typeId; | |
v15->GetTypeObj(&v20, v15); | |
if ( (typeId | 0xB0) == v20.typeId ) | |
v16 = v15; | |
else | |
v15->DecrementRefcount(v15); | |
if ( v16 ) | |
{ | |
v18 = KSharedMemory::Map( | |
v16, | |
&process->pgTable, | |
addr, | |
process, | |
(KMemoryPermission)myPerms, | |
(KMemoryPermission)othersPerms); | |
v16->DecrementRefcount(v16); | |
return v18; | |
} | |
else | |
{ | |
return 0xD9001BF7; | |
} | |
} | |
} | |
} | |
return result; | |
} | |
//----- (FFF04A14) -------------------------------------------------------- | |
Result __fastcall SvcMapProcessMemory(Handle processHandle, u32 addr, u32 size) | |
{ | |
KProcess *volatile curProc; // r7 | |
KProcess *v6; // r0 | |
KProcess *v7; // r5 | |
KProcess *otherProc; // r4 | |
unsigned __int8 v9; // r11 | |
u32 *v10; // r0 | |
Result v11; // r0 | |
signed __int32 *v12; // r1 | |
signed __int32 numPages; // r1 | |
Result v14; // r5 | |
KTypeObj v16; // [sp+8h] [bp-48h] BYREF | |
u32 v17[2]; // [sp+Ch] [bp-44h] FORCED BYREF | |
u32 v18; // [sp+14h] [bp-3Ch] BYREF | |
char v19; // [sp+18h] [bp-38h] BYREF | |
u32 v20; // [sp+1Ch] [bp-34h] BYREF | |
curProc = current.clc.current.process; | |
v6 = (KProcess *)KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, processHandle); | |
v7 = v6; | |
if ( !v6 ) | |
return 0xD9001BF7; | |
otherProc = v6; | |
v6->GetTypeObj((KTypeObj *)&v19, v6); | |
v9 = v20; | |
otherProc->GetTypeObj(&v16, otherProc); | |
if ( (v9 | 0xC5) != v16.typeId ) | |
{ | |
otherProc = 0; | |
v7->DecrementRefcount(v7); | |
} | |
if ( !otherProc ) | |
return 0xD9001BF7; | |
v18 = size >> 12; | |
v17[0] = 0x3F00; | |
v10 = v17; | |
if ( size >> 12 <= 0x3F00 ) | |
v10 = &v18; | |
v11 = KProcessPageTable::MapProcessMemory(&curProc->pgTable, &otherProc->pgTable, addr, 0x100000u, *v10); | |
if ( v11 >= 0 ) | |
{ | |
v17[0] = 0x6000; | |
v12 = (signed __int32 *)&v20; | |
if ( (int)(v18 - 0x7F00) > 0x6000 ) | |
v12 = (signed __int32 *)v17; | |
v20 = v18 - 0x7F00; | |
numPages = *v12; | |
if ( numPages > 0 ) | |
v11 = KProcessPageTable::MapProcessMemory( | |
&curProc->pgTable, | |
&otherProc->pgTable, | |
addr + 0x7F00000, | |
0x8000000u, | |
numPages); | |
} | |
v14 = v11; | |
otherProc->DecrementRefcount(otherProc); | |
return v14; | |
} | |
//----- (FFF04B84) -------------------------------------------------------- | |
Result __fastcall SvcSendSyncRequest(Handle clientSessionHandle) | |
{ | |
KAutoObject *v1; // r0 | |
KAutoObject *v2; // r4 | |
u8 typeId; // r7 | |
int v4; // r1 | |
KClientSession *clientSession; // r5 | |
KSession *parent; // r4 | |
Result v7; // r5 | |
KTypeObj v9; // [sp+0h] [bp-28h] BYREF | |
KTypeObj v10; // [sp+8h] [bp-20h] BYREF | |
v1 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, clientSessionHandle); | |
v2 = v1; | |
if ( !v1 ) | |
return 0xD8E007F7; | |
v1->GetTypeObj(&v9, v1); | |
typeId = v9.typeId; | |
v2->GetTypeObj(&v10, v2); | |
v4 = typeId | 0xA5; | |
clientSession = v4 == v10.typeId ? (KClientSession *)v2 : 0; | |
if ( v4 != v10.typeId ) | |
v2->DecrementRefcount(v2); | |
if ( !clientSession ) | |
return 0xD8E007F7; | |
parent = clientSession->parent; | |
KAutoObject::IncrementRefcount(parent); | |
clientSession->DecrementRefcount(clientSession); | |
v7 = KClientSession::SendSyncRequest(clientSession, current.clc.current.thread); | |
parent->DecrementRefcount(parent); | |
return v7; | |
} | |
//----- (FFF04C84) -------------------------------------------------------- | |
Result __fastcall SvcUnbindInterrupt(s32 interruptId, Handle interruptEventHandle) | |
{ | |
KProcess *curProc; // r5 | |
KInterruptEvent *interruptEventFromHandle; // r0 MAPDST | |
Result v6; // r5 | |
u8 fiq_mask; // r0 | |
int v9; // r6 | |
KFiqState v10; // r1 | |
Result v11; // [sp+4h] [bp-14h] BYREF | |
curProc = current.clc.current.process; | |
interruptEventFromHandle = KHandleTable::ConvertToInterruptEvent( | |
¤t.clc.current.process->handleTable, | |
interruptEventHandle); | |
if ( !interruptEventFromHandle ) | |
return *MakeResultCode(&v11, 0xFBu, 7u, 1u, 0x3F7u); | |
if ( interruptId != KINTNAME_SGI_FIQ ) | |
{ | |
v6 = KProcess::UnbindUserInterruptEventChecked(curProc, interruptEventFromHandle, interruptId); | |
LABEL_4: | |
interruptEventFromHandle->DecrementRefcount(interruptEventFromHandle); | |
return v6; | |
} | |
if ( g_systemControl.targetSystem.isDevUnit ) | |
{ // this path is vulnerable to a double free if you pass a handle to a different KInterruptEvent. | |
// | |
// To mitigate this, instead of fixing it, NN just made the path unreachable on retail units... (11.14) | |
if ( KFiqState::CompareExchangeStrong(&g_fiqState, KFIQSTATE_BOUND, KFIQSTATE_UNBINDING) != KFIQSTATE_BOUND ) | |
{ | |
v6 = 0xD8A007F0; | |
goto LABEL_4; | |
} | |
fiq_mask = CONFIG11.fiq_mask; | |
CONFIG11.fiq_mask = fiq_mask | 2; | |
v9 = KInterruptManager::UnbindKernelInterruptForCore( | |
&g_interruptManager, | |
KINTNAME_SGI_FIQ, | |
__mrc(15, 0, 0, 0, 5) & 3); | |
if ( v9 < 0 ) | |
{ | |
CONFIG11.fiq_mask &= ~2u; | |
v10 = KFIQSTATE_BOUND; | |
} | |
else | |
{ | |
interruptEventFromHandle->irqId = -1; | |
interruptEventFromHandle->DecrementRefcount(interruptEventFromHandle); | |
g_fiqHelper.interruptEvent = 0; | |
v10 = 0; | |
} | |
KFiqState::Set(&g_fiqState, v10); | |
interruptEventFromHandle->DecrementRefcount(interruptEventFromHandle); | |
return v9; | |
} | |
else | |
{ | |
interruptEventFromHandle->DecrementRefcount(interruptEventFromHandle); | |
return 0xD8E007EE; | |
} | |
} | |
//----- (FFF04DF0) -------------------------------------------------------- | |
void __fastcall SvcStopPointOrInvalidId(u32 svcId) | |
{ | |
int pc; // r1 | |
int v2; // r1 | |
_BYTE sp[8]; // [sp+0h] [bp-8h] BYREF | |
if ( svcId != 0xFF ) // stop point | |
{ | |
DispatchDebugEventFromException(DBGEVENT_EXCEPTION, EXCEVENT_UNDEFINED_SYSCALL, svcId); | |
kernelpanic(); | |
} | |
__enable_irq(); | |
pc = *(_DWORD *)(((unsigned int)sp & 0xFFFFF000) + 0xF30); | |
if ( (*(_DWORD *)(((unsigned int)sp & 0xFFFFF000) + 0xF34) & 0x20) != 0 ) | |
v2 = pc - 2; | |
else | |
v2 = pc - 4; | |
*(_DWORD *)(((unsigned int)sp & 0xFFFFF000) + 0xF30) = v2; | |
KPageTable::CleanInvalidateDataCacheRangeLocal(((unsigned int)sp & 0xFFFFF000) + 0xF30, 4u); | |
DispatchDebugEventFromException(DBGEVENT_EXCEPTION, EXCEVENT_STOP_POINT, 0); | |
__disable_irq(); | |
} | |
//----- (FFF04E60) -------------------------------------------------------- | |
Result __fastcall SvcGetThreadContext(ThreadContext *ctx, Handle threadHandle) | |
{ | |
return 0xF8C007F4; | |
} | |
//----- (FFF04E6C) -------------------------------------------------------- | |
Result __fastcall SvcFlushCodeSegment(u32 addr, u32 size) | |
{ | |
return 0xF8C007F4; // On LGY firms, cleaninvs the dcache and invs the icache over the selected range | |
} | |
//----- (FFF04E78) -------------------------------------------------------- | |
Result __fastcall SvcSendSyncRequest1(Handle clientSessionHandle) | |
{ | |
return -121632780; | |
} | |
//----- (FFF04E84) -------------------------------------------------------- | |
Result __fastcall SvcSendSyncRequest2(Handle clientSessionHandle) | |
{ | |
return -121632780; | |
} | |
//----- (FFF04E90) -------------------------------------------------------- | |
Result __fastcall SvcSendSyncRequest3(Handle clientSessionHandle) | |
{ | |
return -121632780; | |
} | |
//----- (FFF04E9C) -------------------------------------------------------- | |
Result __fastcall SvcSendSyncRequest4(Handle clientSessionHandle) | |
{ | |
return -121632780; | |
} | |
//----- (FFF04EA8) -------------------------------------------------------- | |
Result __fastcall SvcTerminateProcess(Handle processHandle) | |
{ | |
KProcess *proc; // r4 | |
proc = KHandleTable::ConvertToProcessAllowPseudoHandle(¤t.clc.current.process->handleTable, processHandle); | |
if ( !proc ) | |
return 0xD8E007F7; | |
if ( current.clc.current.process == proc ) | |
{ | |
proc->DecrementRefcount(proc); | |
KProcess::TerminateCurrentProcess(proc); | |
kernelpanic(); | |
} | |
KProcess::TerminateOtherProcess(proc); | |
proc->DecrementRefcount(proc); | |
return 0; | |
} | |
//----- (FFF04F20) -------------------------------------------------------- | |
Result __fastcall SvcUnmapMemoryBlock(Handle handle, u32 addr) | |
{ | |
Result result; // r0 | |
KProcess *volatile curProc; // r6 | |
KAutoObject *v6; // r0 | |
KAutoObject *v7; // r4 | |
u8 typeId; // r9 | |
int v9; // r1 | |
KSharedMemory *v10; // r7 | |
Result v11; // r5 | |
KTypeObj v12; // [sp+0h] [bp-30h] BYREF | |
KTypeObj v13; // [sp+8h] [bp-28h] BYREF | |
result = addr << 20; | |
if ( addr << 20 ) | |
result = 0xE0E01BF1; | |
if ( result >= 0 ) | |
{ | |
result = addr < 0x8000000 || addr >= 0x14000000 ? 0xE0E01BF5 : 0; | |
if ( result >= 0 ) | |
{ | |
curProc = current.clc.current.process; | |
v6 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, handle); | |
v7 = v6; | |
if ( !v6 ) | |
return 0xD9001BF7; | |
v6->GetTypeObj(&v12, v6); | |
typeId = v12.typeId; | |
v7->GetTypeObj(&v13, v7); | |
v9 = typeId | 0xB0; | |
v10 = v9 == v13.typeId ? (KSharedMemory *)v7 : 0; | |
if ( v9 != v13.typeId ) | |
v7->DecrementRefcount(v7); | |
if ( v10 ) | |
{ | |
v11 = KSharedMemory::Unmap(v10, &curProc->pgTable, addr, curProc); | |
v10->DecrementRefcount(v10); | |
return v11; | |
} | |
else | |
{ | |
return 0xD9001BF7; | |
} | |
} | |
} | |
return result; | |
} | |
//----- (FFF0503C) -------------------------------------------------------- | |
Result __fastcall SvcUnmapProcessMemory(Handle processHandle, u32 addr, u32 size) | |
{ | |
signed __int32 numPages; // r2 | |
KProcessPageTable *p_pgTable; // r6 | |
int *v6; // r0 | |
Result v7; // r0 | |
Result v8; // r4 | |
int *v9; // r0 | |
Result v10; // r0 | |
int v12; // [sp+0h] [bp-20h] BYREF | |
int v13; // [sp+4h] [bp-1Ch] BYREF | |
int v14; // [sp+8h] [bp-18h] BYREF | |
int v15; // [sp+Ch] [bp-14h] BYREF | |
numPages = size >> 12; | |
p_pgTable = ¤t.clc.current.process->pgTable; | |
v6 = &v15; | |
if ( numPages <= 0x3F00 ) | |
v6 = &v13; | |
v13 = numPages; | |
v15 = 0x3F00; | |
v7 = KProcessPageTable::UnmapProcessMemory(¤t.clc.current.process->pgTable, addr, *v6); | |
v12 = 0x6000; | |
v8 = v7; | |
v9 = &v14; | |
if ( v13 - 0x7F00 > 0x6000 ) | |
v9 = &v12; | |
v14 = v13 - 0x7F00; | |
if ( *v9 > 0 ) | |
{ | |
v10 = KProcessPageTable::UnmapProcessMemory(p_pgTable, addr + 0x7F00000, *v9); | |
if ( v8 >= 0 ) | |
v8 = v10; | |
} | |
KPageTable::CleanInvalidateEntireDataCache(); | |
KPageTable::InvalidateEntireInstructionCache(); | |
return v8; | |
} | |
//----- (FFF050F0) -------------------------------------------------------- | |
Result __fastcall SvcBreakDebugProcess(Handle debugHandle) | |
{ | |
KDebug *v1; // r0 | |
KDebug *v2; // r4 | |
Result v4; // r5 | |
v1 = KHandleTable::ConvertCurProcHandleToDebug(debugHandle); | |
v2 = v1; | |
if ( !v1 ) | |
return -654303230; | |
if ( v1->hasDebuggerBreak ) | |
{ | |
v1->DecrementRefcount(v1); | |
return -668983289; | |
} | |
else if ( KDebug::IsProcessTerminated(v1) ) | |
{ | |
v2->DecrementRefcount(v2); | |
return -660594680; | |
} | |
else | |
{ | |
v4 = KDebug::BreakProcess(v2); | |
v2->DecrementRefcount(v2); | |
return v4; | |
} | |
} | |
//----- (FFF05184) -------------------------------------------------------- | |
Result __fastcall SvcOutputDebugString(u32 addr, u32 size) | |
{ | |
int v2; // r3 | |
int v3; // r2 | |
int v5; // r12 | |
u32 endAddr; // lr | |
bool v7; // cf | |
int v8; // r2 | |
bool v9; // cf | |
u32 v10; // r2 | |
int v11; // r3 | |
v2 = 0xE0E01BFD; | |
if ( (size & 0x80000000) != 0 ) | |
v3 = 0xE0E01BFD; | |
else | |
v3 = 0; | |
if ( v3 < 0 ) | |
return 0xE0E01FFD; | |
if ( ~addr >= size ) // if 0xFFFFFFFF - addr < size | |
v2 = 0; | |
if ( v2 < 0 ) | |
return 0xE0E01FFD; | |
v5 = 0xE0E01BF5; | |
endAddr = addr + size; | |
if ( size ) | |
{ | |
v7 = addr >= endAddr - 1; | |
if ( addr <= endAddr - 1 ) | |
v7 = endAddr - 1 >= 0x40000000; | |
if ( !v7 ) | |
goto LABEL_13; | |
} | |
else if ( addr < 0x40000000 ) | |
{ | |
LABEL_13: | |
v8 = 0; | |
goto LABEL_16; | |
} | |
v8 = 0xE0E01BF5; | |
LABEL_16: | |
if ( v8 >= 0 ) | |
return DispatchDebugEvent(DBGEVENT_OUTPUT_STRING, addr, size & 0x7FFFFFFF); | |
if ( size ) // dead code past this point as the first check is more inclusive than all the others | |
{ | |
v9 = addr >= 0x8000000; | |
v10 = endAddr - 1; | |
if ( addr >= 0x8000000 ) | |
v9 = v10 >= addr; | |
if ( v9 && v10 < 0x14000000 ) | |
goto LABEL_23; | |
} | |
else if ( addr >= 0x8000000 && addr < 0x14000000 ) | |
{ | |
LABEL_23: | |
v11 = 0; | |
goto LABEL_27; | |
} | |
v11 = 0xE0E01BF5; | |
LABEL_27: | |
if ( v11 >= 0 ) | |
return DispatchDebugEvent(DBGEVENT_OUTPUT_STRING, addr, size & 0x7FFFFFFF); | |
if ( size ) | |
{ | |
if ( addr > endAddr - 1 || endAddr - 1 >= 0x100000 ) | |
goto LABEL_31; | |
} | |
else if ( addr >= 0x100000 ) | |
{ | |
LABEL_31: | |
v5 = 0; | |
} | |
if ( v5 < 0 ) | |
return 0xD9001C03; | |
return DispatchDebugEvent(DBGEVENT_OUTPUT_STRING, addr, size & 0x7FFFFFFF); | |
} | |
//----- (FFF052A8) -------------------------------------------------------- | |
Result __fastcall SvcReadDebugProcessMemory(u32 dstAddr, Handle debugHandle, u32 addr, u32 size) | |
{ | |
bool v4; // zf | |
int res; // r0 | |
bool v9; // zf | |
KDebug *v10; // r5 | |
Result res2; // r4 | |
v4 = dstAddr == 0; | |
res = debugHandle; | |
if ( v4 ) | |
res = -656406538; | |
if ( !v4 ) | |
{ | |
res = (int)KHandleTable::ConvertCurProcHandleToDebug(res); | |
v10 = (KDebug *)res; | |
v9 = res == 0; | |
if ( !res ) | |
res = 0xD9002002; | |
if ( !v9 ) | |
{ | |
if ( KDebug::IsProcessTerminated((KDebug *)res) ) | |
{ | |
v10->DecrementRefcount(v10); | |
return 0xD8A02008; | |
} | |
else | |
{ | |
if ( ~dstAddr >= size ) // if (UINT32_MAX - outAddr < size) | |
{ | |
if ( KDebug::CheckMemoryAddressRange(v10, dstAddr, size, 0, 1) >= 0 ) | |
{ | |
if ( KDebug::CheckMemoryAddressRange(v10, addr, size, 1, 0) >= 0 ) | |
res2 = KDebug::ReadProcessMemory(v10, dstAddr, addr, size); | |
else | |
res2 = 0xD900200B; | |
} | |
else | |
{ | |
res2 = 0xD900200A; | |
} | |
} | |
else | |
{ | |
res2 = 0xE0E023FD; | |
} | |
v10->DecrementRefcount(v10); | |
return res2; | |
} | |
} | |
} | |
return res; | |
} | |
//----- (FFF053A8) -------------------------------------------------------- | |
Result __fastcall SvcSetThreadPriority(Handle threadHandle, s32 priority) | |
{ | |
Result result; // r0 | |
KThread *thread; // r4 | |
int v7; // r6 | |
if ( (unsigned int)priority >= 0x40 ) | |
result = 0xE0E01BFD; | |
else | |
result = 0; | |
if ( result >= 0 ) | |
{ | |
thread = KHandleTable::ConvertToThreadAllowPseudoHandle(¤t.clc.current.process->handleTable, threadHandle); | |
if ( thread ) | |
{ | |
if ( KProcess::CheckThreadPriority(current.clc.current.process, priority) ) | |
{ | |
v7 = KThread::SetPriority(thread, priority); | |
if ( v7 >= 0 ) | |
{ | |
thread->DecrementRefcount(thread); | |
return v7; | |
} | |
else | |
{ | |
if ( v7 << 22 != 0xFF400000 ) | |
kernelpanic(); | |
thread->DecrementRefcount(thread); | |
return 0xE0E01BFD; | |
} | |
} | |
else | |
{ | |
return 0xD9001BEA; | |
} | |
} | |
else | |
{ | |
return 0xD9001BF7; | |
} | |
} | |
return result; | |
} | |
//----- (FFF05470) -------------------------------------------------------- | |
Result __fastcall SvcContinueDebugEvent(Handle debugHandle, DebugFlags debugFlags) | |
{ | |
KDebug *v3; // r0 | |
KDebug *v4; // r4 | |
unsigned int CPSR; // r5 | |
Result v7; // r6 | |
v3 = KHandleTable::ConvertCurProcHandleToDebug(debugHandle); | |
v4 = v3; | |
if ( !v3 ) | |
return 0xD9002002; | |
if ( KDebug::NeedsContinue(v3) ) | |
{ | |
if ( KDebug::IsProcessTerminated(v4) ) | |
{ | |
v4->DecrementRefcount(v4); | |
return 0xD8A02008; | |
} | |
else | |
{ | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
v7 = KDebug::Continue(v4, debugFlags); | |
__set_CPSR(CPSR); | |
v4->DecrementRefcount(v4); | |
return v7; | |
} | |
} | |
else | |
{ | |
v4->DecrementRefcount(v4); | |
return 0xD8202007; | |
} | |
} | |
//----- (FFF05514) -------------------------------------------------------- | |
Result __fastcall SvcWriteDebugProcessMemory(Handle debugHandle, u32 addr, u32 dstAddr, u32 size) | |
{ | |
Result result; // r0 | |
bool v8; // zf | |
KDebug *v9; // r5 | |
Result v10; // r4 | |
result = (Result)KHandleTable::ConvertCurProcHandleToDebug(debugHandle); | |
v9 = (KDebug *)result; | |
v8 = result == 0; | |
if ( !result ) | |
result = 0xD9002002; | |
if ( !v8 ) | |
{ | |
if ( KDebug::IsProcessTerminated((KDebug *)result) ) | |
{ | |
v9->DecrementRefcount(v9); | |
return 0xD8A02008; | |
} | |
else | |
{ | |
if ( ~addr >= size ) // 0xFFFFFFFF - addr < size | |
{ | |
if ( KDebug::CheckMemoryAddressRange(v9, dstAddr, size, 1, 1) >= 0 ) | |
{ | |
if ( KDebug::CheckMemoryAddressRange(v9, addr, size, 0, 0) >= 0 ) | |
v10 = KDebug::WriteProcessMemory(v9, addr, dstAddr, size); | |
else | |
v10 = 0xD900200A; | |
} | |
else | |
{ | |
v10 = 0xD900200B; | |
} | |
} | |
else | |
{ | |
v10 = 0xE0E023FD; | |
} | |
v9->DecrementRefcount(v9); | |
return v10; | |
} | |
} | |
return result; | |
} | |
//----- (FFF05604) -------------------------------------------------------- | |
Result __fastcall SvcSetProcessResourceLimits(Handle processHandle, Handle resLimitHandle) | |
{ | |
KHandleTable *p_handleTable; // r5 | |
KProcess *proc; // r4 | |
KAutoObject *v5; // r0 | |
KAutoObject *v6; // r4 | |
KProcess *v7; // r8 | |
u8 typeId; // r9 | |
KResourceLimit *resLimit; // r0 MAPDST | |
bool v10; // zf | |
Result v13; // r6 | |
KTypeObj v14; // [sp+0h] [bp-30h] BYREF | |
KTypeObj v15; // [sp+8h] [bp-28h] BYREF | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
if ( processHandle == CUR_PROCESS_HANDLE ) | |
{ | |
proc = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
} | |
else | |
{ | |
v5 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, processHandle); | |
v6 = v5; | |
v7 = 0; | |
if ( v5 ) | |
{ | |
v5->GetTypeObj(&v14, v5); | |
typeId = v14.typeId; | |
v6->GetTypeObj(&v15, v6); | |
if ( (typeId | 0xC5) == v15.typeId ) | |
v7 = (KProcess *)v6; | |
else | |
v6->DecrementRefcount(v6); | |
} | |
proc = v7; | |
} | |
resLimit = KHandleTable::ConvertToResourceLimit(p_handleTable, resLimitHandle); | |
v10 = proc == 0; | |
if ( proc ) | |
v10 = resLimit == 0; | |
if ( v10 ) | |
return 0xD8E007F7; // resleak! | |
v13 = KProcess::SetResourceLimits(proc, resLimit); | |
resLimit->DecrementRefcount(resLimit); | |
proc->DecrementRefcount(proc); | |
return v13; | |
} | |
//----- (FFF05724) -------------------------------------------------------- | |
Result __fastcall SvcGetProcessDebugEvent(DebugEventInfo *outDebugEventInfo, Handle debugHandle) | |
{ | |
Result result; // r0 | |
bool v4; // zf | |
KDebug *v5; // r5 | |
KEventInfo *v6; // r0 | |
KEventInfo *v7; // r4 | |
u32 tidHigh; // r2 | |
KCodeSet *codeSet; // r2 | |
u32 v10; // r1 | |
u32 v11; // r2 | |
u32 processEntrypoint; // r0 | |
KEventInfoData *p_d; // r0 | |
int i; // r1 | |
int v15; // r3 | |
u32 clockTick_high; // r2 | |
u32 address; // r1 | |
u32 size; // r2 | |
u32 permissions; // r3 | |
DebugEventInfo info; // [sp+0h] [bp-40h] BYREF | |
if ( !outDebugEventInfo ) | |
return 0xD8E007F6; | |
result = (Result)KHandleTable::ConvertCurProcHandleToDebug(debugHandle); | |
v5 = (KDebug *)result; | |
v4 = result == 0; | |
if ( !result ) | |
result = 0xD9002002; | |
if ( !v4 ) | |
{ | |
v6 = KDebug::GetFirstEventInfoToFetch((KDebug *)result);// | |
// bug, the mutex should be held by the entire function body, not just during queue get/pop | |
// | |
// same remark with continue | |
v7 = v6; | |
if ( v6 ) | |
{ | |
memset(&info, 0, sizeof(info)); | |
info.fields[0] = v6->type; | |
info.fields[1] = v6->threadId; | |
info.fields[2] = v6->flags; | |
switch ( v6->type ) | |
{ | |
case DBGEVENT_ATTACH_PROCESS: | |
tidHigh = HIDWORD(v6->d.attachProcess.process->codeSet->titleId); | |
info.fields[4] = v6->d.attachProcess.process->codeSet->titleId; | |
info.fields[5] = tidHigh; | |
codeSet = v6->d.attachProcess.process->codeSet; | |
v10 = *(_DWORD *)codeSet->processName; | |
v11 = *(_DWORD *)&codeSet->processName[4]; | |
info.fields[6] = v10; | |
info.fields[7] = v11; | |
info.fields[8] = v6->d.attachProcess.process->pid; | |
if ( v6->ignoreContinue ) | |
info.fields[9] = 1; | |
break; | |
case DBGEVENT_ATTACH_THREAD: | |
info.fields[4] = v6->d.attachThread.creatorThreadId; | |
info.fields[5] = v6->d.attachThread.tls; | |
processEntrypoint = v6->d.attachThread.processEntrypoint; | |
LABEL_18: | |
info.fields[6] = processEntrypoint; | |
break; | |
case DBGEVENT_EXIT_THREAD: | |
case DBGEVENT_EXIT_PROCESS: | |
info.fields[4] = v6->d.exitProcess.reason; | |
break; | |
case DBGEVENT_EXCEPTION: | |
p_d = &v6->d; | |
info.fields[4] = v7->d.exception.type; | |
info.fields[5] = v7->d.exception.address; | |
switch ( info.fields[EXCEVENT_ATTACH_BREAK] )// [4], exception type | |
{ | |
case EXCEVENT_DATA_ABORT: | |
case EXCEVENT_UNALIGNED_DATA_ACCESS: | |
case EXCEVENT_UNDEFINED_SYSCALL: | |
processEntrypoint = v7->d.exception.d.fault.faultInfo; | |
goto LABEL_18; | |
case EXCEVENT_STOP_POINT: | |
info.fields[7] = v7->d.exception.d.fault.faultInfo; | |
processEntrypoint = v7->d.exception.d.fault.stopPointType; | |
goto LABEL_18; | |
case EXCEVENT_USER_BREAK: | |
info.fields[6] = v7->d.exception.d.userBreak.reason; | |
info.fields[7] = v7->d.exception.d.userBreak.croInfo; | |
info.fields[8] = v7->d.exception.d.userBreak.croInfoSize; | |
break; | |
case EXCEVENT_DEBUGGER_BREAK: | |
for ( i = 0; ; ++i ) | |
{ | |
v15 = (MPCORE.scu.cfgr & 3) + 1; | |
if ( v15 <= i ) | |
break; | |
info.fields[i + 6] = p_d->exception.d.debuggerBreak.currentThreadIds[i]; | |
} | |
break; | |
default: | |
goto LABEL_27; | |
} | |
break; | |
case DBGEVENT_SCHEDULE_IN: | |
case DBGEVENT_SCHEDULE_OUT: | |
case DBGEVENT_SYSCALL_IN: | |
case DBGEVENT_SYSCALL_OUT: | |
clockTick_high = HIDWORD(v6->d.syscall.clockTick); | |
info.fields[4] = v6->d.syscall.clockTick; | |
info.fields[5] = clockTick_high; | |
info.fields[6] = v6->d.syscall.svcId; // or cpuId | |
break; | |
case DBGEVENT_OUTPUT_STRING: | |
info.fields[4] = v6->d.outputString.str; | |
info.fields[5] = v6->d.outputString.size; | |
break; | |
case DBGEVENT_MAP: | |
address = v6->d.map.address; | |
size = v6->d.map.size; | |
permissions = v6->d.map.permissions; | |
info.fields[7] = v6->d.map.state; | |
info.fields[4] = address; | |
info.fields[5] = size; | |
info.fields[6] = permissions; | |
break; | |
default: | |
break; | |
} | |
LABEL_27: | |
KDebug::EraseFirstEventInfoToFetchNode(v5); | |
KDebug::ProcessEventInfo(v5, v7->type, v7); | |
v5->DecrementRefcount(v5); | |
if ( CopyBytesToUser(outDebugEventInfo, &info, 0x28u) ) | |
return 0; | |
else | |
return 0xE0E01BF5; | |
} | |
else | |
{ | |
v5->DecrementRefcount(v5); | |
return 0xD8402009; | |
} | |
} | |
return result; | |
} | |
// FFF057AC: control flows out of bounds to FFF057B0 | |
// FFF0589C: control flows out of bounds to FFF058A0 | |
//----- (FFF059D4) -------------------------------------------------------- | |
Result __fastcall SvcWaitSynchronization1(Handle handle, s64 timeout) | |
{ | |
unsigned int v2; // r5 | |
unsigned int v3; // r7 | |
KAutoObject *v5; // r0 | |
KAutoObject *v6; // r4 | |
u8 typeId; // r10 | |
int v8; // r1 | |
KSynchronizationObject *v9; // r6 | |
Result v10; // r5 | |
KTypeObj t1; // [sp+0h] [bp-30h] BYREF | |
KTypeObj v12; // [sp+8h] [bp-28h] BYREF | |
v2 = HIDWORD(timeout); | |
v3 = timeout; | |
if ( timeout < 0 && timeout != -1 ) | |
return 0xD8E007FD; | |
v5 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, handle); | |
v6 = v5; | |
if ( !v5 ) | |
return 0xD8E007F7; | |
v5->GetTypeObj(&t1, v5); | |
typeId = t1.typeId; | |
v6->GetTypeObj(&v12, v6); | |
v8 = typeId | 1; | |
v9 = v8 == v12.typeId ? (KSynchronizationObject *)v6 : 0; | |
if ( v8 != v12.typeId ) | |
v6->DecrementRefcount(v6); | |
if ( !v9 ) | |
return 0xD8E007F7; | |
v10 = KSynchronization::WaitSynchronization1(&g_synchronization, current.clc.current.thread, v9, __SPAIR64__(v2, v3)); | |
v9->DecrementRefcount(v9); | |
return v10; | |
} | |
//----- (FFF05AF4) -------------------------------------------------------- | |
Result __fastcall SvcSetGpuProt(bool allowSystem) | |
{ | |
SetGpuProt(allowSystem); | |
return 0; | |
} | |
//----- (FFF05B04) -------------------------------------------------------- | |
Result __fastcall SvcFlushProcessDataCache(Handle a1, u32 a2, u32 a3) | |
{ | |
KCacheOperator v4; // [sp+0h] [bp-8h] BYREF | |
v4.__vftable = &KCleanInvalidateDataCacheOperator::vt; | |
return KCacheOperator::OperateOnProcessCache(&v4, a1, a2, a3); | |
} | |
//----- (FFF05B30) -------------------------------------------------------- | |
Result __fastcall SvcGetDebugThreadContext( | |
ThreadContext *outThreadContext, | |
Handle debugHandle, | |
u32 tid, | |
ThreadContextControlFlags flags) | |
{ | |
KDebug *v8; // r0 | |
KDebug *debug; // r4 | |
int res; // r5 | |
int v11; // r0 | |
ThreadContext v12; // [sp-E0h] [bp-E0h] BYREF | |
if ( !outThreadContext ) | |
return 0xD8E007F6; | |
v8 = KHandleTable::ConvertCurProcHandleToDebug(debugHandle); | |
debug = v8; | |
if ( !v8 ) | |
return 0xD9002002; | |
if ( KDebug::IsProcessTerminated(v8) ) | |
{ | |
debug->DecrementRefcount(debug); | |
return 0xD8A02008; | |
} | |
else | |
{ | |
res = KDebug::GetPausedThreadContextById(debug, &v12, tid, flags); | |
debug->DecrementRefcount(debug); | |
if ( res >= 0 ) | |
{ | |
if ( CopyWordsToUser(outThreadContext, &v12, 0xCCu) ) | |
v11 = 0; | |
else | |
v11 = 0xE0E01BF5; | |
if ( v11 >= 0 ) | |
return 0; | |
else | |
return 0xD900200A; | |
} | |
else if ( res << 22 == 0xFBC00000 ) | |
{ | |
return 0xD9002004; | |
} | |
else | |
{ | |
return res; | |
} | |
} | |
} | |
//----- (FFF05C24) -------------------------------------------------------- | |
Result __fastcall SvcGetThreadAffinityMask(u8 *outAffinityMask, Handle threadHandle, s32 processorCount) | |
{ | |
char procCount; // r5 | |
char cfgr; // r0 | |
s32 v6; // r0 | |
bool v7; // cc | |
Result result; // r0 | |
KThread *v9; // r0 | |
KThread *v10; // r4 | |
int v11; // r0 | |
u32 v12; // [sp+0h] [bp-18h] BYREF | |
procCount = processorCount; | |
cfgr = MPCORE.scu.cfgr; | |
v6 = (cfgr & 3) + 1; | |
v7 = v6 < processorCount; | |
if ( v6 >= processorCount ) | |
v7 = processorCount < 0; | |
if ( v7 ) | |
result = 0xD8E007FD; | |
else | |
result = 0; | |
if ( result >= 0 ) | |
{ | |
v9 = KHandleTable::ConvertToThreadAllowPseudoHandle(¤t.clc.current.process->handleTable, threadHandle); | |
if ( v9 ) | |
{ | |
v10 = v9; | |
LOBYTE(v12) = v9->affinityMask & ~(-1 << procCount); | |
if ( CopyBytesToUser(outAffinityMask, &v12, 1u) ) | |
v11 = 0; | |
else | |
v11 = 0xE0E01BF5; | |
if ( v11 >= 0 ) | |
{ | |
v10->DecrementRefcount(v10); | |
return 0; | |
} | |
else | |
{ | |
v10->DecrementRefcount(v10); | |
return 0xD9001814; | |
} | |
} | |
else | |
{ | |
return 0xD9001BF7; | |
} | |
} | |
return result; | |
} | |
//----- (FFF05CFC) -------------------------------------------------------- | |
Result __fastcall SvcSetDebugThreadContext( | |
Result debugHandle, | |
u32 tid, | |
const ThreadContext *threadContext, | |
ThreadContextControlFlags flags) | |
{ | |
int v7; // r1 | |
KDebug *v8; // r0 | |
KDebug *v9; // r4 | |
int v10; // r5 | |
ThreadContext v11; // [sp+0h] [bp-E0h] BYREF | |
if ( !threadContext ) | |
debugHandle = 0xD8E007F6; | |
if ( threadContext ) | |
{ | |
if ( CopyWordsFromUser(&v11, threadContext, 0xCCu) ) | |
v7 = 0; | |
else | |
v7 = 0xE0E01BF5; | |
if ( v7 >= 0 ) | |
{ | |
v8 = KHandleTable::ConvertCurProcHandleToDebug(debugHandle); | |
v9 = v8; | |
if ( v8 ) | |
{ | |
if ( KDebug::IsProcessTerminated(v8) ) | |
{ | |
v9->DecrementRefcount(v9); | |
return -660594680; | |
} | |
else | |
{ | |
v10 = KDebug::SetPausedThreadContextById(v9, &v11, tid, flags); | |
v9->DecrementRefcount(v9); | |
if ( v10 < 0 && v10 << 22 == 0xFBC00000 ) | |
return 0xD9002004; | |
else | |
return v10; | |
} | |
} | |
else | |
{ | |
return 0xD9002002; | |
} | |
} | |
else | |
{ | |
return 0xD900200A; | |
} | |
} | |
return debugHandle; | |
} | |
//----- (FFF05DE8) -------------------------------------------------------- | |
Result __fastcall SvcSetHardwareBreakPoint(s32 regId, u32 cr, u32 vr) | |
{ | |
bool v4; // zf | |
bool v5; // zf | |
Result result; // r0 | |
bool v7; // zf | |
if ( regId != 4 ) // this svc sucks, it doesn't broadcast things to other cores | |
// and forgets to dsb | |
{ | |
if ( regId > 4 ) | |
{ | |
v7 = regId == 5; | |
if ( regId != 5 ) | |
v7 = regId == 0x100; // watchpoints | |
if ( !v7 && regId != 0x101 ) | |
goto LABEL_9; | |
} | |
else | |
{ | |
v4 = regId == 0; | |
if ( regId ) | |
v4 = regId == 1; | |
if ( !v4 ) | |
{ | |
v5 = regId == 2; | |
if ( regId != 2 ) | |
v5 = regId == 3; | |
if ( !v5 ) | |
{ | |
LABEL_9: | |
result = 0xD8E007ED; | |
goto LABEL_15; | |
} | |
} | |
} | |
} | |
result = 0; | |
LABEL_15: | |
if ( result >= 0 ) | |
return SetHardwareBreakpoint(regId, cr, vr); | |
return result; | |
} | |
//----- (FFF05E4C) -------------------------------------------------------- | |
Result __fastcall SvcSetThreadAffinityMask(Handle threadHandle, u8 *affinityMask, s32 processorCount) | |
{ | |
return 0xF8C007F4; | |
} | |
//----- (FFF05E58) -------------------------------------------------------- | |
Result __fastcall SvcStoreProcessDataCache(Handle a1, u32 a2, u32 a3) | |
{ | |
KCacheOperator v4; // [sp+0h] [bp-8h] BYREF | |
v4.__vftable = &KCleanDataCacheOperator::vt; | |
return KCacheOperator::OperateOnProcessCache(&v4, a1, a2, a3); | |
} | |
//----- (FFF05E84) -------------------------------------------------------- | |
Result __fastcall SvcTerminateDebugProcess(Handle debugHandle) | |
{ | |
KDebug *v1; // r0 | |
KDebug *v2; // r4 | |
Result result; // r0 | |
int v4; // r5 | |
v1 = KHandleTable::ConvertCurProcHandleToDebug(debugHandle); | |
v2 = v1; | |
if ( !v1 ) | |
return 0xD9002002; | |
v4 = KDebug::TerminateProcess(v1); | |
v2->DecrementRefcount(v2); | |
result = v4; | |
if ( v4 < 0 && v4 << 22 == 0x82000000 ) | |
return 0xD8202007; | |
return result; | |
} | |
//----- (FFF05ED4) -------------------------------------------------------- | |
Result __fastcall SvcGetProcessAffinityMask(u8 *outAffMask, Handle processHandle, s32 coreCount) | |
{ | |
char v4; // r4 | |
char cfgr; // r0 | |
s32 v6; // r0 | |
bool v7; // cc | |
Result result; // r0 | |
KProcess *v9; // r0 | |
KProcess *v10; // r6 | |
int v11; // r0 | |
char v12; // [sp+0h] [bp-18h] BYREF | |
v4 = coreCount; | |
cfgr = MPCORE.scu.cfgr; | |
v6 = (cfgr & 3) + 1; | |
v7 = v6 < coreCount; | |
if ( v6 >= coreCount ) | |
v7 = coreCount < 0; | |
if ( v7 ) | |
result = 0xD8E007FD; | |
else | |
result = 0; | |
if ( result >= 0 ) | |
{ | |
v9 = KHandleTable::ConvertToProcessAllowPseudoHandle(¤t.clc.current.process->handleTable, processHandle); | |
v10 = v9; | |
if ( v9 ) | |
{ | |
v12 = v9->affinityMask & ~(-1 << v4); | |
if ( CopyBytesToUser(outAffMask, &v12, 1u) ) | |
v11 = 0; | |
else | |
v11 = 0xE0E01BF5; | |
if ( v11 >= 0 ) | |
{ | |
v10->DecrementRefcount(v10); | |
return 0; | |
} | |
else | |
{ | |
return 0xD9001814; | |
} | |
} | |
else | |
{ | |
return 0xD9001BF7; | |
} | |
} | |
return result; | |
} | |
//----- (FFF05F90) -------------------------------------------------------- | |
Result __fastcall SvcSetProcessAffinityMask(Handle processHandle, const u8 *affinityMask, s32 numCores) | |
{ | |
char cfgr; // r0 | |
s32 v6; // r0 | |
bool v7; // cc | |
Result result; // r0 | |
int v9; // r0 | |
KProcess *v10; // r0 | |
KProcess *v11; // r5 | |
u32 kernelFlags; // r0 | |
KAffinityMask v13; // [sp+0h] [bp-10h] BYREF | |
cfgr = MPCORE.scu.cfgr; | |
v6 = (cfgr & 3) + 1; | |
v7 = v6 < numCores; | |
if ( v6 >= numCores ) | |
v7 = numCores < 0; | |
if ( v7 ) | |
result = 0xD8E007FD; | |
else | |
result = 0; | |
if ( result >= 0 ) | |
{ | |
if ( CopyBytesFromUser(&v13, affinityMask, 1u) ) | |
v9 = 0; | |
else | |
v9 = 0xE0E01BF5; | |
if ( v9 < 0 ) | |
return 0xD9001814; | |
if ( !v13 ) | |
return 0xE0E01822; | |
v10 = KHandleTable::ConvertToProcessAllowPseudoHandle(¤t.clc.current.process->handleTable, processHandle); | |
v11 = v10; | |
if ( !v10 ) | |
return 0xD9001BF7; | |
kernelFlags = v10->capability.kernelFlags; | |
if ( (kernelFlags & 0xF00) == MEMOP_REGION_BASE ) | |
goto LABEL_22; | |
if ( numCores == 2 ) | |
{ | |
if ( (kernelFlags & 0x2000) != 0 ) | |
{ // can use core2 flag | |
LABEL_22: | |
KAffinityMask::Normalize(&v11->affinityMask, &v13, numCores); | |
v11->DecrementRefcount(v11); | |
return 0; | |
} | |
} | |
else if ( numCores != 3 ) | |
{ | |
goto LABEL_22; | |
} | |
LOBYTE(numCores) = 2; | |
goto LABEL_22; | |
} | |
return result; | |
} | |
//----- (FFF06094) -------------------------------------------------------- | |
Result __fastcall SvcSetThreadIdealProcessor(Handle threadHandle, s32 idealProcessor) | |
{ | |
return 0xF8C007F4; | |
} | |
//----- (FFF060A0) -------------------------------------------------------- | |
Result __fastcall SvcSetProcessIdealProcessor(Handle processHandle, s32 idealProcessor) | |
{ | |
char cfgr; // r1 | |
KProcess *v5; // r0 | |
u32 kernelFlags; // r1 | |
cfgr = MPCORE.scu.cfgr; | |
if ( (cfgr & 3) + 1 <= idealProcessor ) // signed op, whoops | |
// can put < 0 here, causing OOB access | |
return 0xE0E01BFD; | |
v5 = KHandleTable::ConvertToProcessAllowPseudoHandle(¤t.clc.current.process->handleTable, processHandle); | |
if ( !v5 ) | |
return 0xD9001BF7; | |
kernelFlags = v5->capability.kernelFlags; | |
if ( (kernelFlags & 0xF00) == MEMOP_REGION_BASE ) | |
goto LABEL_8; | |
if ( idealProcessor == 2 ) | |
{ | |
if ( (kernelFlags & 0x2000) != 0 ) | |
goto LABEL_8; | |
} | |
else if ( idealProcessor != 3 ) | |
{ | |
LABEL_8: | |
v5->idealProcessor = idealProcessor; | |
v5->DecrementRefcount(v5); // resource leak in some cases... | |
return 0; | |
} | |
return 0xD9001BEA; | |
} | |
//----- (FFF06144) -------------------------------------------------------- | |
s32 SvcGetCurrentProcessorNumber(void) | |
{ | |
return __mrc(15, 0, 0, 0, 5) & 3; | |
} | |
//----- (FFF06150) -------------------------------------------------------- | |
Result __fastcall SvcInvalidateProcessDataCache(Handle a1, u32 a2, u32 a3) | |
{ | |
KCacheOperator v4; // [sp+0h] [bp-8h] BYREF | |
v4.__vftable = &KInvalidateDataCacheOperator::vt; | |
return KCacheOperator::OperateOnProcessCache(&v4, a1, a2, a3); | |
} | |
//----- (FFF0617C) -------------------------------------------------------- | |
Result __fastcall SvcGetResourceLimitLimitValues( | |
s64 *outLimitValues, | |
Handle reslimitHandle, | |
const ResourceLimitType *names, | |
s32 nameCount) | |
{ | |
unsigned int v4; // r7 | |
unsigned int v5; // r10 | |
bool v8; // zf | |
Result result; // r0 | |
KResourceLimit *v11; // r5 | |
int i; // r6 | |
Result v13; // r4 | |
__int64 LimitValue; // [sp+0h] [bp-30h] BYREF | |
ResourceLimitType type; // [sp+8h] [bp-28h] BYREF | |
v8 = outLimitValues == 0; | |
result = 0xD8E007F6; | |
if ( !v8 ) | |
v8 = names == 0; | |
if ( !v8 ) | |
{ | |
result = (unsigned int)nameCount <= 0x7FFFFFFF ? 0 : 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
v11 = KHandleTable::ConvertToResourceLimit(¤t.clc.current.process->handleTable, reslimitHandle); | |
if ( v11 ) | |
{ | |
if ( nameCount > 0 ) | |
{ | |
v5 = 0xD8E007ED; | |
v4 = 0xE0E01BF5; | |
} | |
i = 0; | |
if ( nameCount <= 0 ) | |
{ | |
LABEL_28: | |
v13 = 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
v13 = CopyWordFromUser(&type, &names[i]) ? 0 : v4; | |
if ( v13 < 0 ) | |
break; | |
v13 = (unsigned int)type >= RESLIMIT_MAX ? v5 : 0; | |
if ( v13 < 0 ) | |
break; | |
LimitValue = KResourceLimit::GetLimitValue(v11, type); | |
v13 = CopyBytesToUser(&outLimitValues[i], &LimitValue, 8u) ? 0 : v4; | |
if ( v13 < 0 ) | |
break; | |
if ( ++i >= nameCount ) | |
goto LABEL_28; | |
} | |
} | |
v11->DecrementRefcount(v11); | |
return v13; | |
} | |
else | |
{ | |
return 0xD8E007F7; | |
} | |
} | |
} | |
return result; | |
} | |
// FFF061F4: variable 'v4' is possibly undefined | |
// FFF0620C: variable 'v5' is possibly undefined | |
//----- (FFF06298) -------------------------------------------------------- | |
Result __fastcall SvcSetResourceLimitLimitValues( | |
Handle reslimitHandle, | |
const ResourceLimitType *names, | |
const s64 *values, | |
s32 count) | |
{ | |
Result result; // r0 | |
bool v6; // zf | |
SetResourceLimitLimitValuesArgs args; // [sp+0h] [bp-20h] BYREF | |
result = 0xD8E007F6; | |
v6 = values == 0; | |
if ( values ) | |
v6 = names == 0; | |
if ( !v6 ) | |
{ | |
if ( (unsigned int)count <= 0x7FFFFFF ) | |
result = 0; | |
else | |
result = 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
args.names = names; | |
args.values = values; | |
args.count = count; | |
args.result = 0xE7E3FFFF; | |
args.reslimitHandle = reslimitHandle; | |
if ( CallFuncWithStackAlloc((FuncWithStackAlloc)SetResourceLimitLimitValues, &args, 16 * count) ) | |
return args.result; | |
else | |
return 0xD86007F3; | |
} | |
} | |
return result; | |
} | |
//----- (FFF06310) -------------------------------------------------------- | |
Result __fastcall SvcGetResourceLimitCurrentValues( | |
s64 *outCurrentValues, | |
Handle reslimitHandle, | |
const ResourceLimitType *names, | |
s32 nameCount) | |
{ | |
unsigned int v4; // r7 | |
unsigned int v5; // r10 | |
bool v8; // zf | |
Result result; // r0 | |
KResourceLimit *v11; // r5 | |
int i; // r6 | |
Result v13; // r4 | |
__int64 CurrentValue; // [sp+0h] [bp-30h] BYREF | |
unsigned int val; // [sp+8h] [bp-28h] BYREF | |
v8 = outCurrentValues == 0; | |
result = 0xD8E007F6; | |
if ( !v8 ) | |
v8 = names == 0; | |
if ( !v8 ) | |
{ | |
result = (unsigned int)nameCount <= 0x7FFFFFFF ? 0 : 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
v11 = KHandleTable::ConvertToResourceLimit(¤t.clc.current.process->handleTable, reslimitHandle); | |
if ( v11 ) | |
{ | |
if ( nameCount > 0 ) | |
{ | |
v5 = 0xD8E007ED; | |
v4 = 0xE0E01BF5; | |
} | |
i = 0; | |
if ( nameCount <= 0 ) | |
{ | |
LABEL_28: | |
v13 = 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
v13 = CopyWordFromUser(&val, &names[i]) ? 0 : v4; | |
if ( v13 < 0 ) | |
break; | |
v13 = val >= RESLIMIT_MAX ? v5 : 0; | |
if ( v13 < 0 ) | |
break; | |
CurrentValue = KResourceLimit::GetCurrentValue(v11, (ResourceLimitType)val); | |
v13 = CopyBytesToUser(&outCurrentValues[i], &CurrentValue, 8u) ? 0 : v4; | |
if ( v13 < 0 ) | |
break; | |
if ( ++i >= nameCount ) | |
goto LABEL_28; | |
} | |
} | |
v11->DecrementRefcount(v11); | |
return v13; | |
} | |
else | |
{ | |
return 0xD8E007F7; | |
} | |
} | |
} | |
return result; | |
} | |
// FFF06388: variable 'v4' is possibly undefined | |
// FFF063A0: variable 'v5' is possibly undefined | |
//----- (FFF0642C) -------------------------------------------------------- | |
Result __fastcall SvcBreak(UserBreakType breakReason, u32 croInfoAddr, u32 croInfoSize) | |
{ | |
Result result; // r0 | |
Result v7; // r7 | |
Result IsDebugged; // r0 | |
if ( breakReason <= (unsigned int)USERBREAK_UNLOAD_RO ) | |
result = 0; | |
else | |
result = 0xD8E007ED; | |
if ( result >= 0 ) | |
{ | |
v7 = 0xF8C007F4; | |
if ( !g_systemControl.targetSystem.isDevUnit ) | |
KProcess::TerminateCurrentProcess(current.clc.current.process); | |
switch ( breakReason ) | |
{ | |
case USERBREAK_PANIC: | |
case USERBREAK_ASSERT: | |
case USERBREAK_USER: | |
if ( KProcess::IsDebugged(current.clc.current.process) ) | |
{ | |
IsDebugged = BreakImpl(breakReason, 0, 0); | |
} | |
else | |
{ | |
if ( g_systemControl.targetSystem.kernelPanicOnUserBreak ) | |
ControlSystem(SYSTEMOP_POWER_STATE_CHANGE_SCHEDULING, 0, 0LL); | |
KProcess::TerminateCurrentProcess(current.clc.current.process); | |
IsDebugged = 0; | |
} | |
goto LABEL_13; | |
case USERBREAK_LOAD_RO: | |
case USERBREAK_UNLOAD_RO: | |
IsDebugged = KProcess::IsDebugged(current.clc.current.process); | |
if ( IsDebugged ) | |
IsDebugged = BreakImpl(breakReason, croInfoAddr, croInfoSize); | |
LABEL_13: | |
v7 = IsDebugged; | |
break; | |
default: | |
return v7; | |
} | |
return v7; | |
} | |
return result; | |
} | |
// FFF06474: control flows out of bounds to FFF06478 | |
//----- (FFF0653C) -------------------------------------------------------- | |
void __fastcall IrqHandlerImpl(BOOL user) | |
{ | |
if ( KInterruptManager::HandleIncomingInterrupt(&g_interruptManager) ) | |
KScheduler::TrySwitchingToInterruptTaskMgrThread(current.clc.current.scheduler); | |
if ( user ) | |
{ | |
if ( current.clc.current.thread->shallTerminate ) | |
{ | |
KInterruptTaskManager::EnqueueTask( | |
current.clc.current.interruptTaskManager, | |
¤t.clc.current.thread->KInterruptTask); | |
KScheduler::TrySwitchingThread(current.clc.current.scheduler); | |
} | |
} | |
} | |
//----- (FFF06598) -------------------------------------------------------- | |
Result __fastcall KCodeSet::InitializeDirectly( | |
KCodeSet *this, | |
CodeSetInfo *codeSetInfo, | |
u32 textLoadAddr, | |
u32 rodataLoadAddr, | |
u32 rwDataLoadAddr) | |
{ | |
KCodeSegment::InitializeDirectly(&this->text, &codeSetInfo->text, textLoadAddr); | |
KCodeSegment::InitializeDirectly(&this->rodata, &codeSetInfo->rodata, rodataLoadAddr); | |
KCodeSegment::InitializeDirectly(&this->data, &codeSetInfo->rwdata, rwDataLoadAddr); | |
KCodeSegment::EnsureCacheCoherencyForCode(&this->text); | |
this->numCodePages = codeSetInfo->text_size_total; | |
this->numConstPages = codeSetInfo->ro_size_total; | |
this->numDataPages = codeSetInfo->rw_size_total; | |
*(_QWORD *)this->processName = codeSetInfo->name; | |
this->processName[8] = 0; | |
this->unk1_from_codesetinfo = codeSetInfo->unk1; | |
this->titleId = codeSetInfo->program_id; | |
return 0; | |
} | |
//----- (FFF06620) -------------------------------------------------------- | |
void __fastcall DumpVfpSprsForUserDispatch(ERRF_ExceptionInfo *info) | |
{ | |
__asm { VMRS R1, FPEXC } | |
info->fpexc = _R1; | |
_R1 &= 0x6FFFFFFFu; | |
__asm | |
{ | |
VMSR FPEXC, R1 | |
VMRS R1, FPINST | |
} | |
info->fpinst = _R1; | |
__asm { VMRS R1, FPINST2 } | |
info->fpint2 = _R1; | |
} | |
//----- (FFF06644) -------------------------------------------------------- | |
void __fastcall KScheduler::TrySwitchingToInterruptTaskMgrThread(KScheduler *this) | |
{ | |
this->rescheduleInterruptTaskMgrThread = 1; | |
this->reschedule = 1; | |
if ( !this->disableCount ) | |
KScheduler::SwitchThread(this, 0); | |
this->rescheduleInterruptTaskMgrThread = 0; | |
} | |
//----- (FFF06674) -------------------------------------------------------- | |
Result __fastcall KCodeSegment::InitializeDirectly(KCodeSegment *this, CodeSegmentInfo *segmentInfo, u32 loadAddr) | |
{ | |
u32 totalNumPages; // r2 | |
this->baseUserVa = segmentInfo->addr; | |
this->totalNumPages = segmentInfo->size; | |
totalNumPages = this->totalNumPages; | |
if ( totalNumPages ) | |
KPageGroup::AddRange(&this->pgGroup, loadAddr, totalNumPages); | |
return 0; | |
} | |
//----- (FFF066BC) -------------------------------------------------------- | |
KHandleTable *__fastcall KHandleTable::KHandleTable(KHandleTable *this) | |
{ | |
this->entries = 0; | |
this->firstFreeEntry = 0; | |
this->count = 0; | |
this->mutex.lockingThread = 0; | |
this->mutex.numWaiters = 0; | |
this->mutex.ticketCount = 0; | |
return this; | |
} | |
//----- (FFF066DC) -------------------------------------------------------- | |
Result __fastcall KSharedMemory::Map( | |
KSharedMemory *this, | |
KProcessPageTable *dstPgTable, | |
u32 dstAddr, | |
KProcess *dstProcess, | |
KMemoryPermission myPerms, | |
KMemoryPermission othersPerms) | |
{ | |
u32 tmemAddr; // lr | |
Result result; // r0 | |
unsigned __int8 *v10; // r0 | |
unsigned __int8 v11; // r1 | |
KMemoryPermission ownerPerms; // r1 | |
bool v13; // zf | |
u32 v14; // r12 | |
unsigned __int8 *p_sharedMemMapRefcount; // r0 | |
unsigned __int8 v16; // r1 | |
int v17; // r2 | |
unsigned __int8 *v18; // r0 | |
unsigned __int8 v19; // r1 | |
unsigned __int8 *v20; // r0 | |
unsigned __int8 v21; // r1 | |
unsigned __int8 *v22; // r0 | |
unsigned __int8 v23; // r1 | |
unsigned __int8 *v24; // r1 | |
signed __int8 v25; // r0 | |
unsigned __int8 *v26; // r0 | |
unsigned __int8 v27; // r1 | |
Result v28; // r0 | |
unsigned __int8 *v29; // r0 | |
unsigned __int8 v30; // r1 | |
tmemAddr = this->transferMemAddress; | |
result = 0xE0E01BEE; | |
if ( !tmemAddr ) // sharedmem | |
{ | |
if ( this->ownerProcess == dstProcess ) | |
ownerPerms = this->ownerPerms; | |
else | |
ownerPerms = this->othersPerms; | |
v13 = othersPerms == MEMPERM_DONTCARE; | |
if ( othersPerms == MEMPERM_DONTCARE ) | |
v13 = (myPerms & ~ownerPerms) == 0; // if othersPerms is "don't care", just check if myPerms is allowed | |
if ( !v13 ) | |
return result; | |
if ( this->isDeviceSharedMem ) | |
{ | |
if ( dstAddr ) | |
return result; | |
v14 = KMemoryManager::ConvertSharedMemPaLinearWithAppMemType(this->pgGrp.list.link.next->blockInfo->baseAddress - 0xC0000000); | |
p_sharedMemMapRefcount = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
v16 = __ldrex(p_sharedMemMapRefcount); | |
while ( __strex(v16 + 1, p_sharedMemMapRefcount) );// no overflow check? | |
v17 = KPageTable::CheckAndMapPageGroup(dstPgTable, v14, &this->pgGrp, KMEMSTATE_SHARED, myPerms); | |
if ( v17 < 0 ) | |
{ | |
v18 = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
v19 = __ldrex(v18); | |
while ( __strex(v19 - 1, v18) ); | |
} | |
return v17; | |
} | |
if ( dstAddr ) | |
{ | |
v20 = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
v21 = __ldrex(v20); | |
while ( __strex(v21 + 1, v20) ); | |
v17 = KPageTable::CheckAndMapPageGroup(dstPgTable, dstAddr, &this->pgGrp, KMEMSTATE_SHARED, myPerms); | |
if ( v17 < 0 ) | |
{ | |
v22 = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
v23 = __ldrex(v22); | |
while ( __strex(v23 - 1, v22) ); | |
return v17; | |
} | |
return v17; | |
} | |
return -522183691; | |
} | |
if ( !dstAddr ) | |
return -522183691; | |
if ( this->ownerProcess == dstProcess ) | |
{ | |
v10 = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
v11 = __ldrex(v10); | |
while ( __strex(v11 - 1, v10) ); | |
return 0xD900182C; | |
} | |
if ( othersPerms != MEMPERM_DONTCARE ) | |
{ | |
result = 0xD900182E; // else if tranfermem | |
if ( (this->ownerPerms & ~othersPerms) == 0 && (myPerms & ~this->othersPerms) == 0 ) | |
{ | |
v24 = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
v25 = __ldrex(v24); | |
while ( __strex(v25 + 1, v24) ); | |
if ( v25 > 1 ) | |
{ | |
v26 = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
v27 = __ldrex(v26); | |
while ( __strex(v27 - 1, v26) ); | |
return 0xD900182D; | |
} | |
v28 = KPageTable::CheckAndMapPageGroup(dstPgTable, dstAddr, &this->pgGrp, KMEMSTATE_SHARED, myPerms); | |
v17 = v28; | |
if ( v28 < 0 ) | |
{ | |
v29 = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
v30 = __ldrex(v29); | |
while ( __strex(v30 - 1, v29) ); | |
return v17; | |
} | |
return v17; | |
} | |
} | |
return result; | |
} | |
//----- (FFF069E4) -------------------------------------------------------- | |
Result __fastcall KSharedMemory::Unmap( | |
KSharedMemory *this, | |
KProcessPageTable *dstPgTable, | |
u32 addr, | |
KProcess *dstProcess) | |
{ | |
Result result; // r0 | |
unsigned __int8 *p_sharedMemMapRefcount; // r1 | |
unsigned __int8 v7; // r2 | |
result = KPageTable::CheckAndUnmapPageGroup(dstPgTable, addr, &this->pgGrp); | |
if ( result >= 0 ) | |
{ | |
p_sharedMemMapRefcount = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
v7 = __ldrex(p_sharedMemMapRefcount); | |
while ( __strex(v7 - 1, p_sharedMemMapRefcount) ); | |
} | |
return result; | |
} | |
//----- (FFF06A44) -------------------------------------------------------- | |
Result __fastcall KClientSession::SendSyncRequest(KClientSession *this, KThread *thread) | |
{ | |
int v4; // r5 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
thread->ipcClosedByRemote = 0; | |
thread->ipcPxiBufferTooFragmented = 0; | |
v4 = KServerSession::SendSyncRequest(&this->parent->server, thread); | |
if ( v4 >= 0 ) | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
if ( thread->ipcClosedByRemote ) | |
{ | |
return 0xC920181A; | |
} | |
else if ( thread->ipcPxiBufferTooFragmented ) | |
{ | |
return 0xC8A01836; | |
} | |
else | |
{ | |
return v4; | |
} | |
} | |
else | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return v4; | |
} | |
} | |
//----- (FFF06ACC) -------------------------------------------------------- | |
Result __fastcall KSynchronization::WaitSynchronization1( | |
KSynchronization *this, | |
KThread *thread, | |
KSynchronizationObject *obj, | |
s64 timeout) | |
{ | |
unsigned int ticksLo; // r7 | |
int ticksHi; // r10 | |
unsigned __int64 v8; // kr20_8 | |
Result synchronizationResult; // r4 | |
s64 v10; // r2 | |
KTimerTask *v11; // r1 | |
KTimerTask *v13; // r1 | |
KTimerTask *v14; // r1 | |
KTimerTask *v15; // r1 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( ((((unsigned __int64)-timeout >> 32) & 0x80000000) != 0LL) != __OFSUB__( | |
0, | |
HIDWORD(timeout), | |
(_DWORD)timeout == 0) ) | |
{ | |
v8 = __PAIR64__( | |
(((0x44A2FA85 * (unsigned __int64)(unsigned int)timeout) >> 32) + 0x44A2FA85LL * SHIDWORD(timeout)) >> 32, | |
(unsigned __int64)(0x44A2FA85 * timeout) >> 32) | |
+ KHardwareTimer::GetSystemTick(&g_hardwareTimer); | |
ticksHi = HIDWORD(v8); | |
ticksLo = v8; | |
if ( ((((unsigned __int64)-__SPAIR64__(ticksHi, ticksLo) >> 32) & 0x80000000) != 0LL) == __OFSUB__( | |
0, | |
ticksHi, | |
ticksLo == 0) ) | |
{ | |
ticksLo = 0xFFFFFFFF; | |
ticksHi = 0x7FFFFFFF; | |
} | |
KSchedulerLock::Lock(&g_hardwareTimer.lock); | |
} | |
else | |
{ | |
ticksLo = 0; | |
ticksHi = 0; | |
} | |
if ( obj->TryAcquire(obj, thread) ) | |
{ | |
if ( ((((unsigned __int64)-__SPAIR64__(ticksHi, ticksLo) >> 32) & 0x80000000) != 0LL) != __OFSUB__( | |
0, | |
ticksHi, | |
ticksLo == 0) ) | |
{ | |
KSchedulerLock::UnlockSingleCoreResched(&g_hardwareTimer.lock); | |
ticksLo = 0; | |
ticksHi = 0; | |
} | |
synchronizationResult = 0; | |
v10 = __PAIR64__(ticksHi, ticksLo); | |
if ( ((((unsigned __int64)-__SPAIR64__(ticksHi, ticksLo) >> 32) & 0x80000000) != 0LL) == __OFSUB__(// always true with the above if block | |
0, | |
ticksHi, | |
ticksLo == 0) ) | |
goto LABEL_32; | |
if ( !thread ) | |
{ | |
LABEL_31: | |
v13 = 0; | |
goto LABEL_14; | |
} | |
LABEL_30: | |
v13 = &thread->KTimerTask; | |
LABEL_14: | |
KHardwareTimer::RegisterTask(&g_hardwareTimer, v13, v10); | |
KSchedulerLock::UnlockSingleCoreResched(&g_hardwareTimer.lock); | |
goto LABEL_32; | |
} | |
if ( timeout ) | |
{ | |
thread->signaledObject = 0; | |
thread->synchronizationResult = 0x9401BFE; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_PAUSED); | |
if ( !thread->shallTerminate ) | |
{ | |
KSynchronizationObject::AddWaiter(obj, thread); | |
if ( ((((unsigned __int64)-__SPAIR64__(ticksHi, ticksLo) >> 32) & 0x80000000) != 0LL) != __OFSUB__( | |
0, | |
ticksHi, | |
ticksLo == 0) ) | |
{ | |
if ( thread ) // we need to wait | |
v14 = &thread->KTimerTask; | |
else | |
v14 = 0; | |
KHardwareTimer::RegisterTask(&g_hardwareTimer, v14, __SPAIR64__(ticksHi, ticksLo)); | |
KSchedulerLock::UnlockSingleCoreResched(&g_hardwareTimer.lock); | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
if ( ((((unsigned __int64)-timeout >> 32) & 0x80000000) != 0LL) != __OFSUB__( | |
0, | |
HIDWORD(timeout), | |
(_DWORD)timeout == 0) ) | |
{ | |
if ( thread ) | |
v15 = &thread->KTimerTask; | |
else | |
v15 = 0; | |
KHardwareTimer::CancelTask(&g_hardwareTimer, v15); | |
} | |
synchronizationResult = thread->synchronizationResult; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
KSynchronizationObject::RemoveWaiter(obj, thread); | |
goto LABEL_32; | |
} | |
if ( ((((unsigned __int64)-__SPAIR64__(ticksHi, ticksLo) >> 32) & 0x80000000) != 0LL) != __OFSUB__( | |
0, | |
ticksHi, | |
ticksLo == 0) ) | |
{ | |
KSchedulerLock::UnlockSingleCoreResched(&g_hardwareTimer.lock); | |
ticksLo = 0; | |
ticksHi = 0; | |
} | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_RUNNING); | |
synchronizationResult = 0xD920060D; | |
v10 = __PAIR64__(ticksHi, ticksLo); | |
if ( ((((unsigned __int64)-__SPAIR64__(ticksHi, ticksLo) >> 32) & 0x80000000) != 0LL) == __OFSUB__( | |
0, | |
ticksHi, | |
ticksLo == 0) ) | |
{ | |
LABEL_32: | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return synchronizationResult; | |
} | |
if ( !thread ) | |
goto LABEL_31; | |
goto LABEL_30; | |
} | |
if ( ((((unsigned __int64)-__SPAIR64__(ticksHi, ticksLo) >> 32) & 0x80000000) != 0LL) != __OFSUB__( | |
0, | |
ticksHi, | |
ticksLo == 0) ) | |
{ | |
if ( thread ) | |
v11 = &thread->KTimerTask; | |
else | |
v11 = 0; | |
KHardwareTimer::RegisterTask(&g_hardwareTimer, v11, __SPAIR64__(ticksHi, ticksLo)); | |
KSchedulerLock::UnlockSingleCoreResched(&g_hardwareTimer.lock); | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0x9401BFE; | |
} | |
//----- (FFF06D98) -------------------------------------------------------- | |
void __fastcall KThread::EnableExclusiveVfp(KThread *this) | |
{ | |
KThread *volatile threadWithVfp; // r6 | |
threadWithVfp = current.clc.current.threadWithVfp; | |
KThreadContext::EnableCurrentThreadVfp(); | |
if ( threadWithVfp ) | |
KThreadContext::StoreVfpRegsAndDisable(threadWithVfp->context); | |
KThreadContext::LoadVfp(this->context); | |
do | |
__ldrex((unsigned int *)¤t.clc.current.threadWithVfp); | |
while ( __strex((unsigned int)this, (unsigned int *)¤t.clc.current.threadWithVfp) ); | |
} | |
//----- (FFF06DD8) -------------------------------------------------------- | |
void __fastcall KVfpRegisterDumpHelper::DumpAndDisableVfpRegsForThread(KThread *thread, s32 coreId) | |
{ | |
KCoreLocalContext *p_clc; // r4 | |
unsigned int *p_threadWithVfp; // r4 | |
KThread *threadWithVfp; // t1 | |
KVfpRegisterDumpHelperImpl *v5; // r2 | |
p_clc = &g_coreLocalRegions[coreId].clc; | |
threadWithVfp = p_clc->current.threadWithVfp; | |
p_threadWithVfp = (unsigned int *)&p_clc->current.threadWithVfp; | |
if ( threadWithVfp == thread ) | |
{ | |
if ( (__mrc(15, 0, 0, 0, 5) & 3) == coreId ) | |
{ | |
KThreadContext::StoreVfpRegsAndDisable(thread->context); | |
do | |
__ldrex(p_threadWithVfp); | |
while ( __strex(0, p_threadWithVfp) ); | |
} | |
else | |
{ | |
v5 = &g_vfpRegisterDumpHelper.impls[coreId]; | |
v5->threadToDumpTo = thread; | |
__mcr(15, 0, 0, 7, 10, 5); | |
MPCORE.gicd.sgir = (1 << coreId << 16) & 0xFF0000 | KINTNAME_SGI_DUMP_VFP_REGS; | |
while ( v5->threadToDumpTo ) | |
__yield(); | |
} | |
} | |
} | |
//----- (FFF06E80) -------------------------------------------------------- | |
void __fastcall SetWifiEnabled(bool enable) | |
{ | |
u8 wifi_cnt; // r1 | |
u8 v2; // r1 | |
wifi_cnt = CONFIG11.wifi_cnt; | |
if ( enable ) | |
v2 = wifi_cnt | 1; | |
else | |
v2 = wifi_cnt & ~1; | |
CONFIG11.wifi_cnt = v2; | |
} | |
//----- (FFF06EA0) -------------------------------------------------------- | |
void __fastcall SetGpuProt(BOOL allowSystem) | |
{ | |
int v1; // r1 | |
if ( !allowSystem ) // this svc uses the O3DS field on O3DS, | |
// and the N3DS fields on N3DS (different reg values), | |
// as well as different app mem types? | |
// | |
// | |
// O3DS | |
// | |
// allowSystem || memType==2 (96MB) => 0x26800000 (low byte=3) | |
// memType == 3 (80MB) => 0x25800000 (5) | |
// memType == 4 (74MB) => 0x25000000 (6) | |
// else (0 (64MB) and 5 (32MB), 5 is bugged and will let you GSPWN over more of SYSTEM) | |
// => 0x24800000 (7) | |
allowSystem = 0; | |
if ( g_systemControl.systemHeapGpuAccessAllowed != allowSystem ) | |
{ | |
if ( allowSystem ) // all configs protect the 2nd half (last 0x200000 bytes) of QTM mem: | |
// 0x1F200000..0x1F400000 | |
{ | |
v1 = 0x460; // cutoff at 0x2D000000 | |
// (default at kernel init is 0x2D800000 instead) | |
} | |
else if ( g_systemControl.appMemType == 7 ) // 178MB app mem type, most of system mem locked out | |
{ | |
v1 = 0x490; // cutoff at 0x2B800000 | |
} | |
else | |
{ | |
v1 = 0x4F0; // cutoff at 0x28800000 | |
} | |
CONFIG11.gpuprot = v1 | 0x100; // protect kernel (in axiwram) | |
g_systemControl.systemHeapGpuAccessAllowed = allowSystem; | |
} | |
} | |
//----- (FFF06EF4) -------------------------------------------------------- | |
Result __fastcall SetTimer(Handle timerHandle, s64 initialTimeoutNs, s64 intervalNs) | |
{ | |
bool v3; // nf | |
unsigned int v4; // r6 | |
unsigned int v5; // r8 | |
KTimer *v7; // r9 | |
KAutoObject *v8; // r0 | |
KTimer *v9; // r4 | |
u8 typeId; // r11 | |
Result v11; // r5 | |
KTypeObj v12; // [sp+0h] [bp-38h] BYREF | |
KTypeObj v13; // [sp+8h] [bp-30h] BYREF | |
v4 = HIDWORD(initialTimeoutNs); | |
v3 = initialTimeoutNs < 0; | |
v5 = initialTimeoutNs; | |
if ( initialTimeoutNs >= 0 ) | |
v3 = intervalNs < 0; | |
if ( v3 ) | |
return 0xD8E007FD; | |
v7 = 0; | |
v8 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, timerHandle); | |
v9 = (KTimer *)v8; | |
if ( !v8 ) | |
return 0xD8E007F7; | |
v8->GetTypeObj(&v12, v8); | |
typeId = v12.typeId; | |
v9->GetTypeObj(&v13, v9); | |
if ( (typeId | 0x35) == v13.typeId ) | |
v7 = v9; | |
else | |
v9->DecrementRefcount(v9); | |
if ( !v7 ) | |
return 0xD8E007F7; | |
v11 = KTimer::Set(v7, __SPAIR64__(v4, v5), intervalNs); | |
v7->DecrementRefcount(v7); | |
return v11; | |
} | |
//----- (FFF06FF4) -------------------------------------------------------- | |
Result __fastcall CreatePort( | |
Handle *outSessionPortHandle, | |
Handle *outClientPortHandle, | |
const char *name, | |
s32 maxSessionCount) | |
{ | |
int v7; // r0 | |
Result result; // r0 | |
KHandleTable *p_handleTable; // r6 | |
KPort *v10; // r0 | |
KPort *v11; // r4 | |
int v12; // r5 | |
char kName[11]; // [sp+0h] [bp-38h] BYREF | |
char v14; // [sp+Bh] [bp-2Dh] | |
KTypeObj v15; // [sp+10h] [bp-28h] BYREF | |
*outSessionPortHandle = 0; | |
*outClientPortHandle = 0; | |
if ( name ) | |
{ | |
v7 = CopyStringFromUser(kName, name, 0xCu); | |
if ( v7 < 0 ) | |
{ | |
result = 0xD9001814; | |
goto LABEL_9; | |
} | |
if ( v7 == 12 && v14 ) | |
{ | |
result = 0xE0E0181E; | |
v14 = 0; | |
goto LABEL_9; | |
} | |
} | |
else | |
{ | |
kName[0] = 0; | |
} | |
result = 0; | |
LABEL_9: | |
if ( result >= 0 ) | |
{ | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
v10 = (KPort *)KSlabHeap::Allocate(&g_portAllocator.slabHeap); | |
v11 = v10; | |
if ( v10 ) | |
{ | |
KPort::KPort(v10); | |
KAutoObject::Initialize(v11); | |
} | |
if ( !v11 ) | |
return 0xC8601808; | |
KPort::Initialize(v11, maxSessionCount); | |
v12 = KObjectAllocator::Register(&g_portAllocator, v11); | |
if ( v12 >= 0 ) | |
{ | |
if ( kName[0] ) | |
{ | |
v12 = KObjectName::RegisterObject(&v11->client, kName); | |
*outClientPortHandle = 0; | |
} | |
else | |
{ | |
v11->client.GetTypeObj(&v15, &v11->client); | |
v12 = KHandleTable::Add(p_handleTable, outClientPortHandle, &v11->client, v15.typeId); | |
} | |
if ( v12 >= 0 ) | |
{ | |
v11->server.GetTypeObj(&v15, &v11->server); | |
v12 = KHandleTable::Add(p_handleTable, outSessionPortHandle, &v11->server, v15.typeId); | |
} | |
} | |
v11->server.DecrementRefcount(&v11->server); | |
v11->client.DecrementRefcount(&v11->client); | |
return v12; | |
} | |
return result; | |
} | |
// FFF070A4: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF071C4) -------------------------------------------------------- | |
Result __fastcall OpenThread(Handle *outThreadHandle, Handle processHandle, u32 threadId) | |
{ | |
KProcess *v5; // r6 | |
KHandleTable *p_handleTable; // r7 | |
KProcess *proc; // r4 | |
KAutoObject *v8; // r0 | |
KProcess *v9; // r4 | |
u8 typeId; // r11 | |
KThread *v11; // r0 | |
KThread *v12; // r5 | |
KProcess *owner; // r1 | |
KSynchronizationObject_vtbl *v14; // r0 | |
Result v16; // r6 | |
KThread *v17; // r4 | |
unsigned int v18; // r2 | |
bool v19; // zf | |
unsigned int v20; // r3 | |
KThreadLinkedListNode *next; // r0 | |
KThread *thread; // r2 | |
KTypeObj v23; // [sp+0h] [bp-38h] BYREF | |
KTypeObj v24; // [sp+8h] [bp-30h] BYREF | |
*outThreadHandle = 0; | |
v5 = 0; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
if ( !processHandle ) | |
{ | |
v17 = 0; // all processes | |
v18 = __ldrex((unsigned int *)&g_threadAllocator.container.mutex); | |
v19 = v18 == 0; | |
if ( v18 ) | |
v20 = __strex(v18, (unsigned int *)&g_threadAllocator.container.mutex); | |
else | |
v20 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_threadAllocator.container.mutex); | |
if ( !v18 ) | |
v19 = v20 == 0; | |
if ( !v19 ) | |
KLightMutex::LockImpl(&g_threadAllocator.container.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
next = (KThreadLinkedListNode *)g_threadAllocator.container.list.link.next; | |
if ( (KAutoObjectLinkedListLink *)g_threadAllocator.container.list.link.next != &g_threadAllocator.container.list.link ) | |
{ | |
while ( 1 ) | |
{ | |
thread = next->thread; | |
if ( thread->threadId == threadId ) | |
break; | |
next = next->link.next; | |
if ( next == (KThreadLinkedListNode *)&g_threadAllocator.container.list.link ) | |
goto LABEL_28; | |
} | |
v17 = next->thread; | |
KAutoObject::IncrementRefcount(thread); | |
} | |
LABEL_28: | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_threadAllocator.container.mutex.lockingThread = 0; | |
if ( g_threadAllocator.container.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_threadAllocator.container.mutex); | |
if ( !v17 ) | |
return 0xD9001819; | |
v17->GetTypeObj(&v23, v17); | |
v16 = KHandleTable::Add(p_handleTable, outThreadHandle, v17, v23.typeId); | |
v17->DecrementRefcount(v17); | |
return v16; | |
} | |
if ( processHandle == CUR_PROCESS_HANDLE ) | |
{ | |
proc = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
} | |
else | |
{ | |
v8 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, processHandle); | |
v9 = (KProcess *)v8; | |
if ( !v8 ) | |
return 0xD9001BF7; | |
v8->GetTypeObj(&v23, v8); | |
typeId = v23.typeId; | |
v9->GetTypeObj(&v24, v9); | |
if ( (typeId | 0xC5) == v24.typeId ) | |
v5 = v9; | |
else | |
v9->DecrementRefcount(v9); | |
proc = v5; | |
} | |
if ( !proc ) | |
return 0xD9001BF7; | |
v11 = KThread::FindById(threadId); // it's literally inlined above, though... | |
v12 = v11; | |
if ( !v11 ) | |
{ | |
proc->DecrementRefcount(proc); | |
return 0xD9001819; | |
} | |
owner = v11->owner; | |
v14 = v11->KSynchronizationObject::KAutoObject::__vftable; | |
if ( owner == proc ) | |
{ | |
v14->GetTypeObj(&v23, v12); | |
v16 = KHandleTable::Add(p_handleTable, outThreadHandle, v12, v23.typeId); | |
v12->DecrementRefcount(v12); | |
proc->DecrementRefcount(proc); | |
return v16; | |
} | |
v14->DecrementRefcount(v12); | |
proc->DecrementRefcount(proc); | |
return 0xD9001819; // no proc handle | |
} | |
//----- (FFF07460) -------------------------------------------------------- | |
Result __fastcall RestartDma(Handle dmaObjectHandle, u32 dstAddr, u32 srcAddr, u32 size, DmaRestartFlags restartFlags) | |
{ | |
KDmaObject *v8; // r0 | |
KDmaObject *v9; // r4 | |
KDmaObject *dmaObj; // r9 | |
u8 typeId; // r11 | |
Result result; // r0 | |
int channelId; // r4 | |
KTypeObj v14; // [sp+0h] [bp-38h] BYREF | |
KTypeObj v15; // [sp+8h] [bp-30h] BYREF | |
v8 = (KDmaObject *)KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, dmaObjectHandle); | |
v9 = v8; | |
dmaObj = 0; | |
if ( v8 ) | |
{ | |
v8->GetTypeObj(&v14, v8); | |
typeId = v14.typeId; | |
v9->GetTypeObj(&v15, v9); | |
if ( (typeId | 0x59) == v15.typeId ) | |
dmaObj = v9; | |
else | |
v9->DecrementRefcount(v9); | |
} | |
if ( size <= 0x7FFFFFFF ) | |
result = 0; | |
else | |
result = 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
if ( dmaObj ) | |
{ | |
dmaObj->DecrementRefcount(dmaObj); | |
channelId = dmaObj->channelId; | |
if ( channelId >= 0 ) | |
{ | |
result = KDmaManager::CheckAndPrepareChannelRestart(// check if it's indeed possible to restart | |
// | |
// however there are far fewer checks being done, see | |
// 3dbrew/3DS System Flaws: svcStartInterProcessDma | |
&g_dmaManager, | |
channelId, | |
dstAddr, | |
srcAddr, | |
size, | |
restartFlags); | |
if ( result >= 0 ) | |
return KDmaChannel::Restart(&g_dmaChannels[channelId], dstAddr, srcAddr, size, restartFlags); | |
} | |
else | |
{ | |
return 0xD9400415; | |
} | |
} | |
else | |
{ | |
return 0xD8E007F7; | |
} | |
} | |
return result; | |
} | |
//----- (FFF075A8) -------------------------------------------------------- | |
Result __fastcall CreateEvent(Handle *outEventHandle, ResetType resetType) | |
{ | |
KProcess *process; // r6 | |
KHandleTable *p_handleTable; // r10 | |
KResourceLimit *reslimit; // r5 | |
bool v6; // r9 | |
KEvent *v8; // r0 | |
KEvent *v9; // r4 | |
KEvent *v10; // r0 | |
int v11; // r6 | |
bool v12; // zf | |
KTypeObj v13; // [sp+0h] [bp-38h] BYREF | |
*outEventHandle = 0; | |
process = current.clc.current.process; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
reslimit = current.clc.current.process->reslimit; | |
if ( reslimit ) | |
v6 = KResourceLimit::Reserve(current.clc.current.process->reslimit, RESLIMIT_EVENT, 1); | |
else | |
v6 = 1; | |
if ( !v6 ) | |
return 0xC860180F; | |
v8 = (KEvent *)KSlabHeap::Allocate(&g_eventAllocator.slabHeap); | |
v9 = v8; | |
if ( v8 ) | |
{ | |
v10 = (KEvent *)KSynchronizationObject::KSynchronizationObject(v8); | |
v10->irqId = -1; | |
v10->KInterruptEvent::KSynchronizationObject::KAutoObject::__vftable = &KEvent::vt; | |
v10 = (KEvent *)((char *)v10 + 0x14); | |
v10->KInterruptEvent::KSynchronizationObject::KAutoObject::__vftable = (KInterruptEvent_vtbl *)&KEvent::vt_KInterruptTask;// "next" pointer | |
v10->refcount = 0; | |
KAutoObject::Initialize(v9); | |
} | |
if ( v9 ) | |
{ | |
KEvent::Initialize(v9, process, resetType); | |
reslimit = 0; | |
v11 = KObjectAllocator::Register(&g_eventAllocator, v9); | |
if ( v11 >= 0 ) | |
{ | |
v9->GetTypeObj(&v13, v9); | |
v11 = KHandleTable::Add(p_handleTable, outEventHandle, v9, v13.typeId); | |
} | |
v9->DecrementRefcount(v9); | |
} | |
else | |
{ | |
v11 = 0xC8601801; | |
} | |
v12 = reslimit == 0; | |
if ( reslimit ) | |
v12 = !v6; | |
if ( !v12 ) | |
KResourceLimit::Release(reslimit, RESLIMIT_EVENT, 1); | |
return v11; | |
} | |
// FFF07638: conditional instruction was optimized away because r0.4!=0 | |
// FFF0764C: CONTAINING_RECORD: too small offset 20 for struct 'KEvent' | |
//----- (FFF07720) -------------------------------------------------------- | |
Result __fastcall CreateMutex(Handle *outMutexHandle, BOOL initiallyLocked) | |
{ | |
KProcess *process; // r11 | |
KHandleTable *p_handleTable; // r10 | |
KResourceLimit *reslimit; // r5 | |
bool v6; // r9 | |
KMutex *v8; // r0 | |
KMutex *v9; // r4 | |
KMutex *v10; // r0 | |
int v11; // r6 | |
bool v12; // zf | |
KTypeObj v13; // [sp+0h] [bp-38h] BYREF | |
*outMutexHandle = 0; | |
process = current.clc.current.process; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
reslimit = current.clc.current.process->reslimit; | |
if ( reslimit ) | |
v6 = KResourceLimit::Reserve(current.clc.current.process->reslimit, RESLIMIT_MUTEX, 1); | |
else | |
v6 = 1; | |
if ( !v6 ) | |
return 0xC860180D; | |
v8 = (KMutex *)KSlabHeap::Allocate(&g_mutexAllocator.slabHeap); | |
v9 = v8; | |
if ( v8 ) | |
{ | |
v10 = (KMutex *)KSynchronizationObject::KSynchronizationObject(v8); | |
v10->link.prev = 0; | |
v10->__vftable = &KMutex::vt; | |
v10->link.next = 0; | |
KAutoObject::Initialize(v9); | |
} | |
if ( v9 ) | |
{ | |
KMutex::Initialize(v9, process, initiallyLocked); | |
reslimit = 0; | |
v11 = KObjectAllocator::Register(&g_mutexAllocator, v9); | |
if ( v11 >= 0 ) | |
{ | |
v9->GetTypeObj(&v13, v9); | |
v11 = KHandleTable::Add(p_handleTable, outMutexHandle, v9, v13.typeId); | |
} | |
v9->DecrementRefcount(v9); | |
} | |
else | |
{ | |
v11 = 0xC8601801; | |
} | |
v12 = reslimit == 0; | |
if ( reslimit ) | |
v12 = !v6; | |
if ( !v12 ) | |
KResourceLimit::Release(reslimit, RESLIMIT_MUTEX, 1); | |
return v11; | |
} | |
// FFF077B0: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF07890) -------------------------------------------------------- | |
Result __fastcall CreateTimer(Handle *outTimerHandle, ResetType resetType) | |
{ | |
KProcess *process; // r6 | |
KHandleTable *p_handleTable; // r10 | |
KResourceLimit *reslimit; // r5 | |
bool v6; // r9 | |
KTimer *v8; // r0 | |
KTimer *v9; // r4 | |
KTimer *v10; // r0 | |
int v11; // r6 | |
bool v12; // zf | |
KTypeObj v13; // [sp+0h] [bp-38h] BYREF | |
*outTimerHandle = 0; | |
process = current.clc.current.process; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
reslimit = current.clc.current.process->reslimit; | |
if ( reslimit ) | |
v6 = KResourceLimit::Reserve(current.clc.current.process->reslimit, RESLIMIT_TIMER, 1); | |
else | |
v6 = 1; | |
if ( !v6 ) | |
return 0xC8601810; | |
v8 = (KTimer *)KSlabHeap::Allocate(&g_timerAllocator.slabHeap); | |
v9 = v8; | |
if ( v8 ) | |
{ | |
v10 = (KTimer *)KSynchronizationObject::KSynchronizationObject(v8); | |
v10->KSynchronizationObject::KAutoObject::__vftable = &KTimer::vt; | |
v10 = (KTimer *)((char *)v10 + 20); | |
v10->KSynchronizationObject::KAutoObject::__vftable = (KTimer_vtbl *)&KTimer::vt_KTimerTask;// "next" pointer | |
v10->refcount = 0; | |
KAutoObject::Initialize(v9); | |
} | |
if ( v9 ) | |
{ | |
KTimer::Initialize(v9, process, resetType); | |
reslimit = 0; | |
v11 = KObjectAllocator::Register(&g_timerAllocator, v9); | |
if ( v11 >= 0 ) | |
{ | |
v9->GetTypeObj(&v13, v9); | |
v11 = KHandleTable::Add(p_handleTable, outTimerHandle, v9, v13.typeId); | |
} | |
v9->DecrementRefcount(v9); | |
} | |
else | |
{ | |
v11 = 0xC8601801; | |
} | |
v12 = reslimit == 0; | |
if ( reslimit ) | |
v12 = !v6; | |
if ( !v12 ) | |
KResourceLimit::Release(reslimit, RESLIMIT_TIMER, 1); | |
return v11; | |
} | |
// FFF07920: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF07A00) -------------------------------------------------------- | |
Result __fastcall GetDmaState(DmaState *outDmaState, Handle dmaObjectHandle) | |
{ | |
KDmaObject *v3; // r0 | |
KDmaObject *v4; // r4 | |
KDmaObject *dmaObj; // r5 | |
u8 typeId; // r9 | |
int channelId; // r0 | |
DmaState state; // r0 | |
KTypeObj v10; // [sp+0h] [bp-30h] BYREF | |
KTypeObj v11; // [sp+8h] [bp-28h] BYREF | |
v3 = (KDmaObject *)KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, dmaObjectHandle); | |
v4 = v3; | |
if ( !v3 ) | |
return 0xD8E007F7; | |
dmaObj = v3; | |
v3->GetTypeObj(&v10, v3); | |
typeId = v10.typeId; | |
dmaObj->GetTypeObj(&v11, dmaObj); | |
if ( (typeId | 0x59) != v11.typeId ) | |
{ | |
dmaObj = 0; | |
v4->DecrementRefcount(v4); | |
} | |
if ( !dmaObj ) | |
return 0xD8E007F7; | |
dmaObj->DecrementRefcount(dmaObj); | |
channelId = dmaObj->channelId; // wtf, this is a UaF | |
if ( channelId >= 0 ) | |
state = KDmaChannel::GetDmaState(&g_dmaChannels[channelId]); | |
else | |
state = DMASTATE_DONE; // well, well... | |
*outDmaState = state; | |
return 0; | |
} | |
//----- (FFF07AF4) -------------------------------------------------------- | |
Result __fastcall GetThreadId(u32 *threadId, Handle threadHandle) | |
{ | |
KThread *v3; // r0 | |
*threadId = 0; | |
v3 = KHandleTable::ConvertToThreadAllowPseudoHandle(¤t.clc.current.process->handleTable, threadHandle); | |
if ( !v3 ) | |
return 0xD9001BF7; | |
*threadId = v3->threadId; | |
v3->DecrementRefcount(v3); | |
return 0; | |
} | |
//----- (FFF07B48) -------------------------------------------------------- | |
Result Svc0x74Impl_CodeSetRelated_Stubbed(Handle *codesetHandleMaybe, ...) | |
{ | |
*codesetHandleMaybe = 0; | |
return -121632780; | |
} | |
//----- (FFF07B64) -------------------------------------------------------- | |
Result __fastcall OpenProcess(Handle *outProcessHandle, u32 pid) | |
{ | |
KProcess *v3; // r0 | |
KAutoObject *v4; // r4 | |
KHandleTable *p_handleTable; // r5 | |
Result v7; // r5 | |
KTypeObj v8; // [sp+0h] [bp-18h] BYREF | |
*outProcessHandle = 0; | |
v3 = KProcess::OpenById(pid); | |
v4 = v3; | |
if ( !v3 ) | |
return 0xD9001818; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
v3->GetTypeObj(&v8, v3); | |
v7 = KHandleTable::Add(p_handleTable, outProcessHandle, v4, v8.typeId); | |
v4->DecrementRefcount(v4); | |
return v7; | |
} | |
//----- (FFF07BF4) -------------------------------------------------------- | |
Result __fastcall QueryMemory(MemoryInfo *outMemInfo, u32 *outPgInfo, u32 addr) | |
{ | |
Result result; // r0 | |
u32 size; // r0 | |
char perms; // r2 | |
unsigned __int8 state; // r3 | |
MemoryInfo *__shifted(MemoryInfo,4) p_size; // r4 | |
KMemoryInfo v9; // [sp+0h] [bp-18h] BYREF | |
result = 0; | |
memset(&v9, 0, sizeof(v9)); | |
outMemInfo->baseAddress = 0; | |
outMemInfo->size = 0; | |
outMemInfo->perms = 0; | |
outMemInfo->state = 0; | |
*outPgInfo = 0; | |
if ( addr >= 0x40000000 ) | |
result = 0xE0E01BF5; | |
if ( result >= 0 ) | |
{ | |
result = KPageTable::QueryInfo(¤t.clc.current.process->pgTable, &v9, outPgInfo, addr); | |
if ( result >= 0 ) | |
{ | |
size = v9.size; | |
perms = v9.perms; | |
state = v9.state; | |
outMemInfo->baseAddress = v9.baseAddress; | |
p_size = (MemoryInfo *__shifted(MemoryInfo,4))&outMemInfo->size; | |
ADJ(p_size)->size = size; | |
ADJ(p_size)->perms = perms & KMEMPERM_RW; | |
ADJ(p_size)->state = state; | |
return 0; | |
} | |
} | |
return result; | |
} | |
//----- (FFF07C8C) -------------------------------------------------------- | |
Result __fastcall CreateThread(Handle *outThreadHandle, u32 ep, u32 arg, u32 stackTop, s32 priority, s32 processorId) | |
{ | |
Result result; // r0 | |
char cfgr; // r0 | |
s32 v9; // r0 | |
bool v10; // cc | |
KProcess *volatile parentProcess; // r6 | |
u32 kernelFlags; // r1 | |
KResourceLimit *reslimit; // r7 | |
bool v14; // r8 | |
KThread *v15; // r0 | |
KThread *v16; // r4 | |
KThread *v17; // r0 | |
int v18; // r9 | |
bool v19; // zf | |
int v20; // r6 | |
KTypeObj v21; // [sp+0h] [bp-40h] BYREF | |
*outThreadHandle = 0; | |
if ( (unsigned int)priority < 0x40 ) | |
result = 0; | |
else | |
result = 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
cfgr = MPCORE.scu.cfgr; | |
v9 = (cfgr & 3) + 1; | |
v10 = v9 <= processorId; | |
if ( v9 > processorId ) | |
v10 = processorId <= -3; | |
result = v10 ? 0xD8E007FD : 0; // I think this is return (procId <= -3 || procId >= numCores) ? 0xD8E007FD : 0; | |
if ( result >= 0 ) | |
{ | |
parentProcess = current.clc.current.process; | |
v19 = !KProcess::CheckThreadPriority(current.clc.current.process, priority); | |
result = 0xD9001BEA; | |
if ( !v19 ) | |
{ | |
kernelFlags = parentProcess->capability.kernelFlags; | |
if ( (kernelFlags & 0xF00) != MEMOP_REGION_BASE )// only allow core3 for base sysmodules | |
// only allow core2 for base sysmodules who have bit2 kernelflag set | |
{ | |
if ( processorId == 2 ) | |
{ | |
if ( (kernelFlags & 0x2000) == 0 ) | |
return result; | |
} | |
else if ( processorId == 3 ) | |
{ | |
return result; | |
} | |
} | |
reslimit = parentProcess->reslimit; | |
if ( reslimit ) | |
v14 = KResourceLimit::Reserve(parentProcess->reslimit, RESLIMIT_THREAD, 1); | |
else | |
v14 = 1; | |
if ( v14 ) | |
{ | |
v15 = (KThread *)KSlabHeap::Allocate(&g_threadAllocator.slabHeap); | |
v16 = v15; | |
if ( v15 ) | |
{ | |
v17 = (KThread *)KSynchronizationObject::KSynchronizationObject(v15); | |
v17->KTimerTask::next = 0; | |
v17->KWorkerTask::next = 0; | |
v17->KInterruptTask::next = 0; | |
v17->KSynchronizationObject::KAutoObject::__vftable = &KThread::vt; | |
v17->KTimerTask::__vftable = &KThread::vt_KTimerTask; | |
v17->KWorkerTask::__vftable = &KThread::vt_KWorkerTask; | |
v17->KInterruptTask::KInterruptHandler::__vftable = &KThread::vt_KInterruptTask; | |
v17->shallTerminate = 0; | |
v17->wantedLightMutex = 0; | |
v17->synchronizationResult = 0xE7E3FFFF; | |
v17->syncObjectWaitAllList.count = 0; | |
v17->syncObjectWaitAllList.link.next = (KSynchronizationObjectLinkedListNode *)&v17->syncObjectWaitAllList.link; | |
v17->heldMutexListRootNode = 0; | |
v17->syncObjectWaitAllList.link.prev = (KSynchronizationObjectLinkedListNode *)&v17->syncObjectWaitAllList.link; | |
v17->mutexTryingToAcquireList.count = 0; | |
v17->mutexTryingToAcquireList.link.next = (KMutexLinkedListNode *)&v17->mutexTryingToAcquireList.link; | |
v17->mutexTryingToAcquireList.link.prev = (KMutexLinkedListNode *)&v17->mutexTryingToAcquireList.link; | |
v17->affinityMask = 0; | |
v17->owner = 0; | |
v17->context = 0; | |
KAutoObject::Initialize(v16); | |
} | |
if ( v16 ) | |
{ | |
v18 = KThread::InitializeUserThread(v16, ep, arg, stackTop, priority, processorId, parentProcess); | |
if ( v18 >= 0 && (v18 = KObjectAllocator::Register(&g_threadAllocator, v16), v18 >= 0) ) | |
{ | |
v16->GetTypeObj(&v21, v16); | |
v20 = KHandleTable::Add(&parentProcess->handleTable, outThreadHandle, v16, v21.typeId); | |
if ( v20 >= 0 ) | |
KThread::PrepareToRun(v16); | |
else | |
v16->DecrementRefcount(v16); | |
return v20; | |
} | |
else | |
{ | |
v16->DecrementRefcount(v16); | |
return v18; | |
} | |
} | |
else | |
{ | |
v19 = reslimit == 0; | |
if ( reslimit ) | |
v19 = !v14; | |
if ( !v19 ) | |
KResourceLimit::Release(reslimit, RESLIMIT_THREAD, 1); | |
return 0xC8601803; | |
} | |
} | |
else | |
{ | |
return 0xC860180C; | |
} | |
} | |
} | |
} | |
return result; | |
} | |
// FFF07DA8: conditional instruction was optimized away because r0.4!=0 | |
// FFF07E78: conditional instruction was optimized away because zf.1==1 | |
// FFF07EFC: conditional instruction was optimized away because zf.1==1 | |
// FFF07F70: conditional instruction was optimized away because zf.1==1 | |
//----- (FFF07FC0) -------------------------------------------------------- | |
Result __fastcall GetProcessId(u32 *outPid, Handle processHandle) | |
{ | |
KProcess *v3; // r0 | |
*outPid = 0; | |
v3 = KHandleTable::ConvertToProcessAllowPseudoHandle(¤t.clc.current.process->handleTable, processHandle); | |
if ( !v3 ) | |
return 0xD9001BF7; | |
*outPid = v3->pid; | |
v3->DecrementRefcount(v3); | |
return 0; | |
} | |
//----- (FFF08010) -------------------------------------------------------- | |
Result __fastcall AcceptSession(Handle *outServerSessionHandle, Handle serverPortHandle) | |
{ | |
KHandleTable *p_handleTable; // r6 | |
KAutoObject *v4; // r0 | |
KAutoObject *v5; // r4 | |
u8 typeId; // r9 | |
int v7; // r1 | |
KServerPort *serverPort; // r5 | |
KServerPort *v9; // r4 | |
KServerSession *v10; // r0 | |
KAutoObject *v11; // r5 | |
Result v12; // r6 | |
KTypeObj v14; // [sp+0h] [bp-30h] BYREF | |
KTypeObj v15; // [sp+8h] [bp-28h] BYREF | |
*outServerSessionHandle = 0; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
v4 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, serverPortHandle); | |
v5 = v4; | |
if ( !v4 ) | |
return 0xD8E007F7; | |
v4->GetTypeObj(&v14, v4); | |
typeId = v14.typeId; | |
v5->GetTypeObj(&v15, v5); | |
v7 = typeId | 0x55; | |
serverPort = v7 == v15.typeId ? (KServerPort *)v5 : 0; | |
if ( v7 != v15.typeId ) | |
v5->DecrementRefcount(v5); | |
v9 = serverPort; | |
if ( !serverPort ) | |
return 0xD8E007F7; | |
v10 = KServerPort::AcceptSession(serverPort); | |
v11 = v10; | |
if ( v10 ) | |
{ | |
v10->GetTypeObj(&v14, v10); | |
v12 = KHandleTable::Add(p_handleTable, outServerSessionHandle, v11, v14.typeId); | |
v11->DecrementRefcount(v11); | |
v9->DecrementRefcount(v9); | |
return v12; | |
} | |
else | |
{ | |
v9->DecrementRefcount(v9); | |
return 0xD8401823; | |
} | |
} | |
//----- (FFF08160) -------------------------------------------------------- | |
Result __fastcall ConnectToPort(Handle *outClientSessionHandle, const char *name) | |
{ | |
int v3; // r0 | |
Result result; // r0 | |
KHandleTable *p_handleTable; // r7 | |
KClientPort *Object; // r0 | |
KClientPort *v7; // r5 | |
KClientPort *v8; // r4 | |
u8 typeId; // r10 | |
int v10; // r5 | |
KClientSession *v11; // r4 | |
Result v12; // r4 | |
KClientSession *v13; // [sp+0h] [bp-48h] BYREF | |
KTypeObj v14; // [sp+8h] [bp-40h] BYREF | |
char kName[12]; // [sp+10h] [bp-38h] BYREF | |
KTypeObj v16; // [sp+20h] [bp-28h] BYREF | |
*outClientSessionHandle = 0; | |
if ( name ) | |
{ | |
v3 = CopyStringFromUser(kName, name, 0xCu); | |
if ( v3 < 0 ) | |
{ | |
result = 0xD9001814; | |
goto LABEL_9; | |
} | |
if ( v3 == 12 && kName[11] ) | |
{ | |
result = 0xE0E0181E; | |
kName[11] = 0; | |
goto LABEL_9; | |
} | |
} | |
else | |
{ | |
kName[0] = 0; | |
} | |
result = 0; | |
LABEL_9: | |
if ( result >= 0 ) | |
{ | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
Object = (KClientPort *)KObjectName::FindObject(kName); | |
v7 = Object; | |
if ( !Object ) | |
return 0xD88007FA; | |
v8 = Object; | |
Object->GetTypeObj(&v14, Object); | |
typeId = v14.typeId; | |
v8->GetTypeObj(&v16, v8); | |
if ( (typeId | 0x65) != v16.typeId ) | |
{ | |
v8 = 0; | |
v7->DecrementRefcount(v7); | |
} | |
if ( v8 ) | |
{ | |
v10 = KClientPort::CreateSession(v8, &v13); | |
v8->DecrementRefcount(v8); | |
if ( v10 >= 0 ) | |
{ | |
v11 = v13; | |
v13->GetTypeObj(&v14, v13); | |
v12 = KHandleTable::Add(p_handleTable, outClientSessionHandle, v11, v14.typeId); | |
v13->DecrementRefcount(v13); | |
return v12; | |
} | |
else | |
{ | |
return v10; | |
} | |
} | |
else | |
{ | |
return 0xD88007FA; | |
} | |
} | |
return result; | |
} | |
//----- (FFF082F4) -------------------------------------------------------- | |
Result __fastcall ControlMemory(u32 *outAddr, u32 addr0, u32 addr1, u32 size, u8 op, u32 perms) | |
{ | |
Result result; // r0 | |
u32 endAddr; // r11 | |
KProcess *volatile curProc; // r9 | |
u32 LinearAddrRangeBase; // r0 | |
u32 linearAddrLimit; // r1 | |
bool v14; // cc | |
u32 v15; // r0 | |
bool v16; // cf | |
bool v17; // cf | |
bool v18; // cf | |
u32 v19; // r0 | |
u32 linearAddrLimit2; // r0 | |
u32 v21; // r1 | |
u32 v22; // r0 | |
bool v23; // cf | |
bool v24; // cf | |
bool v25; // cf | |
u32 v26; // r0 | |
bool v27; // cf | |
u32 v28; // r0 | |
bool v29; // zf | |
bool v30; // zf | |
u32 isLoader; // r0 | |
int v32; // r7 | |
bool v33; // zf | |
int v34; // r4 | |
int outAddra[2]; // [sp+Ch] [bp-3Ch] BYREF | |
*outAddr = 0; | |
result = addr0 << 20; // check if aligned | |
if ( addr0 << 20 ) | |
result = 0xE0E01BF1; | |
if ( result >= 0 ) | |
{ | |
result = addr1 << 20; | |
if ( addr1 << 20 ) | |
result = 0xE0E01BF1; | |
if ( result >= 0 ) | |
{ | |
result = size << 20; | |
if ( size << 20 ) | |
result = 0xE0E01BF2; | |
if ( result >= 0 ) | |
{ | |
switch ( op ) // check operation | |
{ | |
case MEMOP_FREE: | |
case MEMOP_ALLOC: | |
case MEMOP_MAP: | |
case MEMOP_UNMAP: | |
case MEMOP_PROT: | |
result = 0; | |
break; | |
default: | |
result = 0xE0E01BEE; | |
break; | |
} | |
if ( result >= 0 ) | |
{ | |
endAddr = addr0 + size; | |
curProc = current.clc.current.process; | |
if ( op == 3 ) | |
{ | |
if ( (op & 0x10000) == 0 ) | |
{ | |
LABEL_57: | |
if ( addr0 && addr0 - 0x8000000 < 0x6000000 && endAddr > 0xE000000 )// | |
// if normal, check if addr0 is within | |
// | |
// * 0x08000000..0x0E000000 (size not properly checked for that subrange) | |
// * 0x10000000..0x14000000 (not freeable!) | |
return 0xE0E01BFD; | |
if ( size ) | |
{ | |
v25 = addr0 >= 0x8000000; | |
v26 = endAddr - 1; | |
if ( addr0 >= 0x8000000 ) | |
v25 = v26 >= addr0; | |
if ( v25 && v26 < 0x14000000 ) | |
goto LABEL_67; | |
} | |
else if ( addr0 >= 0x8000000 && addr0 < 0x14000000 ) | |
{ | |
LABEL_67: | |
result = 0; | |
goto LABEL_71; | |
} | |
result = 0xE0E01BF5; | |
LABEL_71: | |
if ( result < 0 ) | |
return result; | |
if ( op == MEMOP_MAP || op == MEMOP_UNMAP ) | |
{ | |
if ( size ) | |
{ | |
v27 = addr1 >= 0x100000; // looks like we can remap heap to grow data/bss | |
v28 = addr1 + size - 1; | |
if ( addr1 >= 0x100000 ) | |
v27 = v28 >= addr1; | |
if ( v27 && v28 < 0x14000000 ) | |
goto LABEL_80; | |
} | |
else if ( addr1 >= 0x100000 && addr1 < 0x14000000 ) | |
{ | |
LABEL_80: | |
result = 0; | |
goto LABEL_84; | |
} | |
result = 0xE0E01BF5; | |
LABEL_84: | |
if ( result < 0 ) | |
return result; | |
} | |
LABEL_85: | |
if ( !size ) | |
return 0; | |
if ( op == 1 ) | |
goto LABEL_97; | |
v29 = perms == 0; | |
if ( perms ) | |
v29 = perms == 1; | |
if ( v29 ) | |
goto LABEL_95; | |
v30 = perms == 2; | |
if ( perms != 2 ) | |
v30 = perms == 3; | |
if ( v30 ) | |
LABEL_95: | |
result = 0; | |
else | |
result = 0xE0E01BEE; | |
if ( result >= 0 ) | |
{ | |
LABEL_97: | |
isLoader = curProc->pid; | |
v32 = op & 0xFFFFFF; | |
if ( isLoader != 1 ) | |
isLoader = 0; | |
if ( (-isLoader & v32 & 0xF00) == 0 ) | |
v32 = curProc->capability.kernelFlags & 0xF00 | op & 0xFFF0FF; | |
v33 = op == 3; | |
if ( op == 3 ) | |
v33 = isLoader == 0; | |
if ( !v33 || KProcess::ReserveResource(current.clc.current.process, RESLIMIT_COMMIT, size) ) | |
{ | |
outAddra[0] = 0; | |
v34 = KProcessPageTable::ControlMemory( | |
&curProc->pgTable, | |
(u32 *)outAddra, | |
addr0, | |
addr1, | |
size, | |
v32, | |
perms); | |
if ( v34 >= 0 ) | |
{ | |
if ( op == MEMOP_FREE ) // bug here, if loader alloc fails, this will grow the reslimit | |
KProcess::ReleaseResource(current.clc.current.process, RESLIMIT_COMMIT, size); | |
*outAddr = outAddra[0]; | |
return 0; | |
} | |
else | |
{ | |
if ( op == 3 ) | |
KProcess::ReleaseResource(current.clc.current.process, RESLIMIT_COMMIT, size); | |
return v34; | |
} | |
} | |
else | |
{ | |
return -933226486; | |
} | |
} | |
return result; | |
} | |
if ( addr0 ) | |
{ | |
LinearAddrRangeBase = KProcess::GetLinearAddrRangeBase(current.clc.current.process); | |
if ( LinearAddrRangeBase == 0x14000000 ) | |
linearAddrLimit = 0x1C000000; | |
else | |
linearAddrLimit = LinearAddrRangeBase + 0x10000000; | |
if ( size ) | |
{ | |
v14 = LinearAddrRangeBase > addr0; | |
v15 = endAddr - 1; | |
if ( v14 ) | |
return 0xE0E01BF5; | |
v16 = addr0 >= v15; | |
if ( addr0 <= v15 ) | |
v16 = v15 >= linearAddrLimit; | |
if ( v16 ) | |
return 0xE0E01BF5; | |
} | |
else | |
{ | |
v17 = LinearAddrRangeBase >= addr0; | |
if ( LinearAddrRangeBase <= addr0 ) | |
v17 = addr0 >= linearAddrLimit; | |
if ( v17 ) | |
return 0xE0E01BF5; | |
} | |
} | |
if ( !addr1 ) | |
goto LABEL_85; | |
} | |
else | |
{ | |
if ( op != 1 ) | |
goto LABEL_57; | |
if ( size ) | |
{ | |
v18 = addr0 >= 0x8000000; | |
v19 = endAddr - 1; | |
if ( addr0 >= 0x8000000 ) | |
v18 = v19 >= addr0; | |
if ( v18 && v19 < 0x10000000 ) | |
goto LABEL_85; | |
} | |
else if ( addr0 >= 0x8000000 && addr0 < 0x10000000 ) | |
{ | |
goto LABEL_85; | |
} | |
linearAddrLimit2 = KProcess::GetLinearAddrRangeBase(current.clc.current.process); | |
if ( linearAddrLimit2 == 0x14000000 ) | |
v21 = 0x1C000000; | |
else | |
v21 = linearAddrLimit2 + 0x10000000; | |
if ( size ) | |
{ | |
v14 = linearAddrLimit2 > addr0; | |
v22 = endAddr - 1; | |
if ( !v14 ) | |
{ | |
v23 = addr0 >= v22; | |
if ( addr0 <= v22 ) | |
v23 = v22 >= v21; | |
if ( !v23 ) | |
goto LABEL_85; | |
} | |
} | |
else | |
{ | |
v24 = linearAddrLimit2 >= addr0; | |
if ( linearAddrLimit2 <= addr0 ) | |
v24 = addr0 >= v21; | |
if ( !v24 ) | |
goto LABEL_85; | |
} | |
} | |
return 0xE0E01BF5; | |
} | |
} | |
} | |
} | |
return result; | |
} | |
// FFF08358: control flows out of bounds to FFF0835C | |
// FFF082F4: using guessed type u32 outAddr; | |
//----- (FFF086A0) -------------------------------------------------------- | |
Result __fastcall CreateCodeSet(Handle *outHandle, CodeSetInfo *codeSetInfo, u32 textPtr, u32 rodataPtr, u32 dataPtr) | |
{ | |
bool v6; // zf | |
Result result; // r0 | |
bool v10; // zf | |
KProcessPageTable *p_pgTable; // r10 | |
KCodeSet *v12; // r0 | |
KCodeSet *v13; // r4 | |
int v14; // r6 | |
KHandleTable *p_handleTable; // r6 | |
KTypeObj v16; // [sp+0h] [bp-68h] BYREF | |
CodeSetInfo codeSetInfoKern; // [sp+8h] [bp-60h] BYREF | |
v6 = codeSetInfo == 0; | |
if ( codeSetInfo ) | |
v6 = textPtr == 0; | |
*outHandle = 0; | |
result = 0xD8E007F6; | |
if ( !v6 ) | |
{ | |
v10 = rodataPtr == 0; | |
if ( rodataPtr ) | |
v10 = dataPtr == 0; | |
if ( !v10 ) | |
{ | |
result = CopyBytesFromUser(&codeSetInfoKern, codeSetInfo, 0x40u) ? 0 : 0xE0E01BF5; | |
if ( result >= 0 ) | |
{ | |
p_pgTable = ¤t.clc.current.process->pgTable; | |
v12 = (KCodeSet *)KSlabHeap::Allocate(&g_codeSetAllocator.slabHeap); | |
v13 = v12; | |
if ( v12 ) | |
{ | |
KCodeSet::KCodeSet(v12); | |
KAutoObject::Initialize(v13); | |
} | |
if ( v13 ) | |
{ | |
KCodeSet::Initialize(v13, &codeSetInfoKern, p_pgTable, textPtr, rodataPtr, dataPtr); | |
v14 = KObjectAllocator::Register(&g_codeSetAllocator, v13); | |
if ( v14 >= 0 ) | |
{ | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
v13->GetTypeObj(&v16, v13); | |
v14 = KHandleTable::Add(p_handleTable, outHandle, v13, v16.typeId); | |
} | |
v13->DecrementRefcount(v13); | |
return v14; | |
} | |
else | |
{ | |
return 0xD8601402; | |
} | |
} | |
} | |
} | |
return result; | |
} | |
// FFF0872C: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF087E4) -------------------------------------------------------- | |
Result __fastcall CreateProcess(Handle *outProcessHandle, Handle codeSetHandle, u32 *kernelCaps, s32 numKernelCaps) | |
{ | |
Result result; // r0 | |
KHandleTable *p_handleTable; // r6 | |
KAutoObject *v9; // r0 | |
KAutoObject *v10; // r5 | |
u8 typeId; // r11 | |
int v12; // r1 | |
KCodeSet *v13; // r4 | |
KCodeSet *codeSet; // r5 | |
KProcess *v15; // r0 | |
KProcess *v16; // r4 | |
KProcess *v17; // r0 | |
KHandleTable *__shifted(KProcess,0xDC) v18; // r0 | |
KProcess *v19; // r10 | |
int v20; // r4 | |
KTypeObj v21; // [sp+0h] [bp-38h] BYREF | |
KTypeObj v22; // [sp+8h] [bp-30h] BYREF | |
*outProcessHandle = 0; | |
if ( (unsigned int)numKernelCaps <= 0x7FFFFFFF ) | |
result = 0; | |
else | |
result = 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
if ( numKernelCaps <= 0 || kernelCaps ) | |
{ // note: kernelCaps addr not validated (!) | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
v9 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, codeSetHandle); | |
v10 = v9; | |
if ( !v9 ) | |
return 0xD9001BF7; | |
v9->GetTypeObj(&v21, v9); | |
typeId = v21.typeId; | |
v10->GetTypeObj(&v22, v10); | |
v12 = typeId | 0x68; | |
if ( v12 == v22.typeId ) | |
v13 = (KCodeSet *)v10; | |
else | |
v13 = 0; | |
if ( v12 != v22.typeId ) | |
v10->DecrementRefcount(v10); | |
codeSet = v13; | |
if ( v13 ) | |
{ | |
v15 = (KProcess *)KSlabHeap::Allocate(&g_processAllocator.slabHeap); | |
v16 = v15; | |
if ( v15 ) | |
{ | |
v17 = (KProcess *)KSynchronizationObject::KSynchronizationObject(v15); | |
v17->KSynchronizationObject::KAutoObject::__vftable = &KProcess::vt; | |
v17->KWorkerTask::__vftable = &KProcess::vt_KWorkerTask; | |
v17->next = 0; | |
v17->pgTable.mutex.lockingThread = 0; | |
v17->pgTable.mutex.numWaiters = 0; | |
v17->pgTable.mutex.ticketCount = 0; | |
v17->pgTable.memoryBlockMgr.blocks.link.next = (KMemoryBlockLinkedListNode *)&v17->pgTable.memoryBlockMgr.blocks.link; | |
v17->pgTable.memoryBlockMgr.blocks.count = 0; | |
v17->pgTable.memoryBlockMgr.blocks.link.prev = (KMemoryBlockLinkedListNode *)&v17->pgTable.memoryBlockMgr.blocks.link; | |
v17->kernAllocatedForProcess = 0; | |
v17->threadLocalPages.link.next = (KThreadLocalPageLinkedListNode *)&v17->threadLocalPages.link; | |
v17->threadLocalPages.count = 0; | |
v17->threadLocalPages.link.prev = (KThreadLocalPageLinkedListNode *)&v17->threadLocalPages.link; | |
v17->state = KPROCSTATE_CREATED; | |
v17->affinityMask = 0; | |
v17->threadCount = 0; | |
v17->capability.kernelFlags = 0; | |
v17->capability.intendedKernelVersion = 0; | |
v18 = KHandleTable::KHandleTable(&v17->handleTable); | |
ADJ(v18)->unused_234 = 0; | |
ADJ(v18)->unused_238 = 0LL; | |
ADJ(v18)->unused_240 = 0LL; | |
ADJ(v18)->unused_248 = 0LL; | |
ADJ(v18)->unused_250 = 0LL; | |
ADJ(v18)->unused_258 = 0LL; | |
ADJ(v18)->unused_260 = 0LL; | |
ADJ(v18)->unused_268 = 0LL; | |
KAutoObject::Initialize(v16); | |
} | |
v19 = v16; | |
if ( v16 ) | |
{ | |
v20 = KProcess::Initialize(v16, codeSet, kernelCaps, numKernelCaps); | |
codeSet->DecrementRefcount(codeSet); | |
if ( v20 >= 0 ) | |
{ | |
v20 = KObjectAllocator::Register(&g_processAllocator, v19); | |
if ( v20 < 0 | |
|| (v19->GetTypeObj(&v21, v19), | |
v20 = KHandleTable::Add(p_handleTable, outProcessHandle, v19, v21.typeId), | |
v20 < 0) ) | |
{ | |
v19->DecrementRefcount(v19); | |
} | |
} | |
return v20; | |
} | |
else | |
{ | |
return 0xC860180A; | |
} | |
} | |
else | |
{ | |
return 0xD9001BF7; | |
} | |
} | |
else | |
{ | |
return 0xD8E007F6; | |
} | |
} | |
return result; | |
} | |
// FFF088E4: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF08A74) -------------------------------------------------------- | |
Result __fastcall CreateSession(Handle *outServerSessionHandle, Handle *outClientSessionHandle) | |
{ | |
KSession *v4; // r0 | |
KSession *v5; // r4 | |
KSession *v6; // r0 | |
KServerSession *__shifted(KSession,8) v7; // r0 | |
KClientSession *__shifted(KSession,0x2C) v8; // r0 | |
KHandleTable *p_handleTable; // r7 | |
int v11; // r5 | |
KTypeObj v12; // [sp+0h] [bp-20h] BYREF | |
*outServerSessionHandle = 0; | |
*outClientSessionHandle = 0; | |
v4 = (KSession *)KSlabHeap::Allocate(&g_sessionAllocator.slabHeap); | |
v5 = v4; | |
if ( v4 ) | |
{ | |
v6 = (KSession *)KAutoObject::KAutoObject(v4); | |
v6->__vftable = &KSession::vt; | |
v7 = (KServerSession *__shifted(KSession,8))KSynchronizationObject::KSynchronizationObject(&v6->server); | |
ADJ(v7)->server.__vftable = &KServerSession::vt; | |
ADJ(v7)->server.syncRequestWaitList.link.prev = 0; | |
ADJ(v7)->server.syncRequestWaitList.link.next = 0; | |
ADJ(v7)->server.currentRequestingThread = 0; | |
v8 = (KClientSession *__shifted(KSession,0x2C))KSynchronizationObject::KSynchronizationObject(&ADJ(v7)->client); | |
ADJ(v8)->client.__vftable = &KClientSession::vt; | |
ADJ(v8)->client.status = 0; | |
KAutoObject::Initialize(v5); | |
} | |
if ( !v5 ) | |
return 0xC8601809; | |
KSession::Initialize(v5, 0); | |
KObjectAllocator::Register(&g_sessionAllocator, v5); | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
v5->server.GetTypeObj(&v12, &v5->server); | |
v11 = KHandleTable::Add(p_handleTable, outServerSessionHandle, &v5->server, v12.typeId); | |
if ( v11 >= 0 ) | |
{ | |
v5->client.GetTypeObj(&v12, &v5->client); | |
v11 = KHandleTable::Add(p_handleTable, outClientSessionHandle, &v5->client, v12.typeId); | |
} | |
v5->server.DecrementRefcount(&v5->server); | |
v5->client.DecrementRefcount(&v5->client); | |
return v11; | |
} | |
// FFF08AB8: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF08BF0) -------------------------------------------------------- | |
Result __fastcall GetHandleInfo(s64 *out, Handle handle, s32 type) | |
{ | |
KProcess *volatile process; // r4 | |
KProcess *v6; // r0 | |
KThread *volatile thread; // r4 | |
KProcess *v9; // r4 | |
int creationTime; // r5 | |
int creationTime_high; // r6 | |
u8 typeId; // r10 | |
KTypeObj v13; // [sp+0h] [bp-30h] BYREF | |
KTypeObj v14; // [sp+8h] [bp-28h] BYREF | |
*out = 0LL; | |
if ( handle == CUR_PROCESS_HANDLE ) | |
{ | |
process = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
v6 = process; | |
} | |
else if ( handle == CUR_THREAD_HANDLE ) | |
{ | |
thread = current.clc.current.thread; | |
KAutoObject::IncrementRefcount(current.clc.current.thread); | |
v6 = (KProcess *)thread; | |
} | |
else | |
{ | |
v6 = (KProcess *)KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, handle); | |
} | |
if ( !v6 ) | |
return 0xD8E007F7; | |
v9 = v6; | |
creationTime = 0; | |
creationTime_high = 0; | |
switch ( type ) | |
{ | |
case 0: | |
v6->GetTypeObj(&v13, v6); | |
typeId = v13.typeId; | |
v9->GetTypeObj(&v14, v9); | |
if ( (typeId | 0xC5) == v14.typeId ) | |
{ | |
creationTime = v9->creationTime; | |
creationTime_high = HIDWORD(v9->creationTime); | |
} | |
goto LABEL_19; | |
case 1: | |
creationTime = v6->refcount - 1; | |
creationTime_high = creationTime >> 31; | |
LABEL_19: | |
*(_DWORD *)out = creationTime; | |
*((_DWORD *)out + 1) = creationTime_high; | |
v9->DecrementRefcount(v9); | |
return 0; | |
case 2: | |
case 0x32107: | |
goto LABEL_19; | |
} | |
v6->DecrementRefcount(v6); | |
return 0xD8E007ED; | |
} | |
//----- (FFF08D68) -------------------------------------------------------- | |
Result __fastcall GetSystemInfo(s64 *out, s32 type, s32 subType) | |
{ | |
u32 v4; // r0 | |
u32 v5; // r7 | |
u32 v6; // r6 | |
u32 TotalNumPages; // r0 | |
u32 regionSize; // r1 | |
u32 v9; // r0 | |
u32 v10; // r0 | |
u32 v11; // r0 | |
v4 = 0; | |
if ( type == 2 ) | |
v4 = (u32)&g_memoryManager; | |
*(_DWORD *)out = 0; | |
*((_DWORD *)out + 1) = 0; | |
if ( type == 2 ) | |
{ | |
v4 = *(_DWORD *)(v4 + 0x70); // ->pgMgr.kernelMemoryUsage | |
} | |
else if ( type > 2 ) | |
{ | |
if ( type != 3 && type == 26 ) | |
v4 = 5; | |
} // number of initial processes | |
else if ( !type ) | |
{ | |
if ( subType ) | |
{ | |
switch ( subType ) | |
{ | |
case 1: | |
TotalNumPages = KPageHeap::GetTotalNumPages(&g_memoryManager.applicationHeap); | |
regionSize = g_memoryManager.applicationHeap.regionSize; | |
v9 = TotalNumPages << 12; | |
break; | |
case 2: | |
v10 = KPageHeap::GetTotalNumPages(&g_memoryManager.systemHeap); | |
regionSize = g_memoryManager.systemHeap.regionSize; | |
v9 = v10 << 12; | |
break; | |
case 3: | |
v11 = KPageHeap::GetTotalNumPages(&g_memoryManager.baseHeap); | |
regionSize = g_memoryManager.baseHeap.regionSize; | |
v9 = v11 << 12; | |
break; | |
default: | |
goto LABEL_21; | |
} | |
v4 = regionSize - v9; | |
goto LABEL_21; | |
} | |
v5 = KPageHeap::GetTotalNumPages(&g_memoryManager.applicationHeap) << 12; | |
v6 = KPageHeap::GetTotalNumPages(&g_memoryManager.systemHeap) << 12; | |
v4 = 0x10000000 - v5 - v6 - (KPageHeap::GetTotalNumPages(&g_memoryManager.baseHeap) << 12); | |
} | |
LABEL_21: | |
*(_DWORD *)out = v4; | |
*((_DWORD *)out + 1) = 0; | |
return 0; | |
} | |
//----- (FFF08E7C) -------------------------------------------------------- | |
Result __fastcall GetThreadInfo(s64 *outValue, Handle threadHandle, s32 type) | |
{ | |
KThread *volatile thread; // r4 | |
KAutoObject *v4; // r0 | |
KAutoObject *v5; // r4 | |
u8 typeId; // r7 | |
int v7; // r1 | |
KThread *v8; // r5 | |
KTypeObj v10; // [sp+0h] [bp-28h] BYREF | |
KTypeObj v11; // [sp+8h] [bp-20h] BYREF | |
*outValue = 0LL; | |
if ( threadHandle == CUR_THREAD_HANDLE ) | |
{ | |
thread = current.clc.current.thread; | |
KAutoObject::IncrementRefcount(current.clc.current.thread); | |
} | |
else | |
{ | |
v4 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, threadHandle); | |
v5 = v4; | |
if ( !v4 ) | |
return 0xD8E007F7; | |
v4->GetTypeObj(&v10, v4); | |
typeId = v10.typeId; | |
v5->GetTypeObj(&v11, v5); | |
v7 = typeId | 0x8D; | |
if ( v7 == v11.typeId ) | |
v8 = (KThread *)v5; | |
else | |
v8 = 0; | |
if ( v7 != v11.typeId ) | |
v5->DecrementRefcount(v5); | |
thread = v8; | |
} | |
if ( thread ) | |
{ | |
thread->DecrementRefcount(thread); | |
return 0xD8E007ED; | |
} | |
return 0xD8E007F7; | |
} | |
//----- (FFF08F84) -------------------------------------------------------- | |
Result __fastcall GetThreadList(s32 *outNumThreads, u32 *outTids, s32 maxNumThreads, Handle processHandle) | |
{ | |
Result result; // r0 | |
GetThreadListArgs v6; // [sp+0h] [bp-20h] BYREF | |
*outNumThreads = 0; | |
if ( !outTids ) | |
return 0xD8E007F6; | |
if ( (unsigned int)maxNumThreads <= 0x1FFFFFFF ) | |
result = 0; | |
else | |
result = 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
v6.outThreadIds = outTids; | |
v6.maxNumThreads = maxNumThreads; | |
v6.processHandle = processHandle; | |
v6.result = 0xE7E3FFFF; | |
v6.outNumThreads = outNumThreads; | |
if ( CallFuncWithStackAlloc((FuncWithStackAlloc)GetThreadListImpl, &v6, 4 * maxNumThreads) ) | |
return v6.result; | |
else | |
return 0xD86007F3; | |
} | |
return result; | |
} | |
//----- (FFF09000) -------------------------------------------------------- | |
Result __fastcall SignalAndWait(s32 *idx, Handle signal, Handle *handles, s32 numHandles, bool waitAll, s64 timeout) | |
{ | |
*idx = 0; | |
return 0xF8C007F4; | |
} | |
//----- (FFF09014) -------------------------------------------------------- | |
Result __fastcall GetProcessInfo(s64 *outValue, Handle processHandle, s32 type) | |
{ | |
KProcess *volatile process; // r4 | |
KAutoObject *v6; // r0 | |
KAutoObject *v7; // r4 | |
unsigned __int8 v8; // r9 | |
int v9; // r1 | |
KProcess *v10; // r8 | |
Result result; // r0 | |
KLightMutex *p_mutex; // r0 | |
unsigned int v13; // r2 | |
bool v14; // zf | |
unsigned int v15; // r3 | |
s64 TotalPrivateOrSharedMemSize; // r8 | |
KLightMutex *v17; // r0 | |
__int64 v18; // r0 | |
unsigned int *p_pgTable; // r0 | |
unsigned int v20; // r2 | |
bool v21; // zf | |
unsigned int v22; // r3 | |
KLightMutex *v23; // r0 | |
unsigned int v24; // r2 | |
bool v25; // zf | |
unsigned int v26; // r3 | |
KLightMutex *v27; // r0 | |
unsigned int v28; // r2 | |
bool v29; // zf | |
unsigned int v30; // r3 | |
Result QtmStaticMappedConversionOffset; // r0 | |
Result v32; // r5 | |
unsigned int v33; // [sp+0h] [bp-30h] BYREF | |
int v34; // [sp+4h] [bp-2Ch] | |
char v35; // [sp+8h] [bp-28h] BYREF | |
int v36; // [sp+Ch] [bp-24h] | |
*outValue = 0LL; | |
if ( processHandle == CUR_PROCESS_HANDLE ) | |
{ | |
process = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
} | |
else | |
{ | |
v6 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, processHandle); | |
v7 = v6; | |
if ( !v6 ) | |
return 0xD8E007F7; | |
v6->GetTypeObj((KTypeObj *)&v33, v6); // I wish "force new variable" actually worked | |
v8 = v34; | |
v7->GetTypeObj((KTypeObj *)&v35, v7); | |
v9 = v8 | 0xC5; | |
if ( v9 == (unsigned __int8)v36 ) | |
v10 = (KProcess *)v7; | |
else | |
v10 = 0; | |
if ( v9 != (unsigned __int8)v36 ) | |
v7->DecrementRefcount(v7); | |
process = v10; | |
} | |
if ( !process ) | |
return 0xD8E007F7; | |
switch ( type ) | |
{ | |
case 0: | |
p_mutex = &process->pgTable.mutex; | |
v13 = __ldrex((unsigned int *)&process->pgTable); | |
v14 = v13 == 0; | |
if ( v13 ) | |
v15 = __strex(v13, (unsigned int *)p_mutex); | |
else | |
v15 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)p_mutex); | |
if ( !v13 ) | |
v14 = v15 == 0; | |
if ( !v14 ) | |
KLightMutex::LockImpl(p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
TotalPrivateOrSharedMemSize = KMemoryBlockManger::GetTotalPrivateOrSharedMemSize(&process->pgTable.memoryBlockMgr); | |
v17 = &process->pgTable.mutex; | |
__mcr(15, 0, 0, 7, 10, 5); | |
process->pgTable.mutex.lockingThread = 0; | |
if ( process->pgTable.mutex.numWaiters > 0 ) | |
goto LABEL_48; | |
goto LABEL_21; | |
case 1: | |
p_pgTable = (unsigned int *)&process->pgTable; | |
v20 = __ldrex((unsigned int *)&process->pgTable); | |
v21 = v20 == 0; | |
if ( v20 ) | |
v22 = __strex(v20, p_pgTable); | |
else | |
v22 = __strex((unsigned int)current.clc.current.thread, p_pgTable); | |
if ( !v20 ) | |
v21 = v22 == 0; | |
if ( !v21 ) | |
KLightMutex::LockImpl((KLightMutex *)p_pgTable); | |
__mcr(15, 0, 0, 7, 10, 5); | |
v17 = &process->pgTable.mutex; | |
TotalPrivateOrSharedMemSize = process->pgTable.unk_24; | |
__mcr(15, 0, 0, 7, 10, 5); | |
process->pgTable.mutex.lockingThread = 0; | |
if ( process->pgTable.mutex.numWaiters > 0 ) | |
goto LABEL_48; | |
goto LABEL_21; | |
case 2: | |
v23 = &process->pgTable.mutex; | |
v24 = __ldrex((unsigned int *)&process->pgTable); | |
v25 = v24 == 0; | |
if ( v24 ) | |
v26 = __strex(v24, (unsigned int *)v23); | |
else | |
v26 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)v23); | |
if ( !v24 ) | |
v25 = v26 == 0; | |
if ( !v25 ) | |
KLightMutex::LockImpl(v23); | |
__mcr(15, 0, 0, 7, 10, 5); | |
TotalPrivateOrSharedMemSize = KMemoryBlockManger::GetTotalPrivateMemSize(&process->pgTable.memoryBlockMgr); | |
v17 = &process->pgTable.mutex; | |
__mcr(15, 0, 0, 7, 10, 5); | |
process->pgTable.mutex.lockingThread = 0; | |
if ( process->pgTable.mutex.numWaiters > 0 ) | |
goto LABEL_48; | |
goto LABEL_21; | |
case 3: | |
v27 = &process->pgTable.mutex; | |
v28 = __ldrex((unsigned int *)&process->pgTable); | |
v29 = v28 == 0; | |
if ( v28 ) | |
v30 = __strex(v28, (unsigned int *)v27); | |
else | |
v30 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)v27); | |
if ( !v28 ) | |
v29 = v30 == 0; | |
if ( !v29 ) | |
KLightMutex::LockImpl(v27); | |
__mcr(15, 0, 0, 7, 10, 5); | |
v17 = &process->pgTable.mutex; | |
TotalPrivateOrSharedMemSize = process->pgTable.unk_28; | |
__mcr(15, 0, 0, 7, 10, 5); | |
process->pgTable.mutex.lockingThread = 0; | |
if ( process->pgTable.mutex.numWaiters > 0 ) | |
LABEL_48: | |
KLightMutex::UnlockImpl(v17); | |
LABEL_21: | |
v18 = TotalPrivateOrSharedMemSize | |
+ KHandleTable::GetTotalAllocatedSize(&process->handleTable) | |
+ process->kernAllocatedForProcess; | |
goto LABEL_62; | |
case 4: | |
LODWORD(v18) = process->handleTable.count; | |
goto LABEL_54; | |
case 5: | |
LODWORD(v18) = process->handleTable.maxCount; | |
goto LABEL_54; | |
case 6: | |
LODWORD(v18) = process->unused_234; | |
goto LABEL_54; | |
case 7: | |
KProcess::DumpThreadIds(process, (s32 *)&v33, 0, 0); | |
LODWORD(v18) = v33; | |
goto LABEL_54; | |
case 8: | |
LODWORD(v18) = process->maxAllowedThreadCount;// always 0 | |
goto LABEL_54; | |
case 19: | |
v18 = process->capability.kernelFlags & 0xF00LL; | |
goto LABEL_62; | |
case 20: | |
v18 = 0x20000000 - KProcess::GetLinearAddrRangeBase(process); | |
goto LABEL_62; | |
case 21: | |
QtmStaticMappedConversionOffset = KProcess::GetQtmStaticMappedConversionOffset((s32 *)&v33, process); | |
if ( QtmStaticMappedConversionOffset < 0 ) | |
goto LABEL_64; | |
LODWORD(v18) = v33; | |
LABEL_54: | |
v18 = (int)v18; | |
goto LABEL_62; | |
case 22: | |
QtmStaticMappedConversionOffset = KProcess::GetQtmStaticMappedBase((s32 *)&v33, process); | |
if ( QtmStaticMappedConversionOffset >= 0 ) | |
goto LABEL_61; | |
goto LABEL_64; | |
case 23: | |
QtmStaticMappedConversionOffset = KProcess::GetQtmStaticMappedSize((s32 *)&v33, process); | |
if ( QtmStaticMappedConversionOffset >= 0 ) | |
{ | |
LABEL_61: | |
v18 = v33; | |
LABEL_62: | |
*outValue = v18; | |
process->DecrementRefcount(process); | |
result = 0; | |
} | |
else | |
{ | |
LABEL_64: | |
v32 = QtmStaticMappedConversionOffset; | |
process->DecrementRefcount(process); | |
result = v32; | |
} | |
break; | |
default: | |
process->DecrementRefcount(process); | |
return 0xD8E007ED; | |
} | |
return result; | |
} | |
// FFF090F0: control flows out of bounds to FFF090F4 | |
//----- (FFF09410) -------------------------------------------------------- | |
Result __fastcall GetProcessList(s32 *outNumProcesses, u32 *outPids, s32 maxNumProcesses) | |
{ | |
Result result; // r0 | |
GetProcessListArgs v5; // [sp+0h] [bp-18h] BYREF | |
*outNumProcesses = 0; | |
if ( !outPids ) | |
return 0xD8E007F6; | |
if ( (unsigned int)maxNumProcesses <= 0x1FFFFFFF ) | |
result = 0; | |
else | |
result = 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
v5.outPids = outPids; | |
v5.maxNumProcesses = maxNumProcesses; | |
v5.result = 0xE7E3FFFF; | |
v5.outNumProcesses = outNumProcesses; | |
if ( CallFuncWithStackAlloc((FuncWithStackAlloc)GetProcessListImpl, &v5, 4 * maxNumProcesses) ) | |
return v5.result; | |
else | |
return 0xD86007F3; | |
} | |
return result; | |
} | |
//----- (FFF0948C) -------------------------------------------------------- | |
Result __fastcall CreateSemaphore(Handle *outSemaphoreHandle, s32 initialCount, s32 maxCount) | |
{ | |
Result result; // r0 | |
KProcess *process; // r9 | |
KHandleTable *p_handleTable; // r11 | |
KResourceLimit *reslimit; // r5 | |
bool v9; // r8 | |
KSynchronizationObject *v10; // r0 | |
KSemaphore *v11; // r4 | |
KSemaphore *v12; // r0 | |
int v13; // r9 | |
bool v14; // zf | |
KTypeObj v15; // [sp+0h] [bp-38h] BYREF | |
*outSemaphoreHandle = 0; | |
if ( (unsigned int)initialCount <= 0x7FFFFFFF ) | |
result = 0; | |
else | |
result = 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
if ( initialCount <= maxCount ) | |
{ | |
process = current.clc.current.process; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
reslimit = current.clc.current.process->reslimit; | |
if ( reslimit ) | |
v9 = KResourceLimit::Reserve(current.clc.current.process->reslimit, RESLIMIT_SEMAPHORE, 1); | |
else | |
v9 = 1; | |
if ( v9 ) | |
{ | |
v10 = (KSynchronizationObject *)KSlabHeap::Allocate(&g_semaphoreAllocator.slabHeap); | |
v11 = (KSemaphore *)v10; | |
if ( v10 ) | |
{ | |
v12 = (KSemaphore *)KSynchronizationObject::KSynchronizationObject(v10); | |
v12->next = 0; | |
v12->irqId = -1; | |
v12->KInterruptEvent::KSynchronizationObject::KAutoObject::__vftable = (KInterruptEvent_vtbl *)&KSemaphore::vt;// | |
// interrupt task part | |
v12 = (KSemaphore *)((char *)v12 + 0x14); | |
v12->KInterruptEvent::KSynchronizationObject::KAutoObject::__vftable = (KInterruptEvent_vtbl *)&KSemaphore::vt_KInterruptTask; | |
v12->waiters.link.next = 0; | |
KAutoObject::Initialize(v11); | |
} | |
if ( v11 ) | |
{ | |
KSemaphore::Initialize(v11, process, initialCount, maxCount); | |
reslimit = 0; | |
v13 = KObjectAllocator::Register(&g_semaphoreAllocator, v11); | |
if ( v13 >= 0 ) | |
{ | |
v11->GetTypeObj(&v15, v11); | |
v13 = KHandleTable::Add(p_handleTable, outSemaphoreHandle, v11, v15.typeId); | |
} | |
v11->DecrementRefcount(v11); | |
} | |
else | |
{ | |
v13 = 0xC8601801; | |
} | |
v14 = reslimit == 0; | |
if ( reslimit ) | |
v14 = !v9; | |
if ( !v14 ) | |
KResourceLimit::Release(reslimit, RESLIMIT_SEMAPHORE, 1); | |
return v13; | |
} | |
else | |
{ | |
return 0xC860180E; | |
} | |
} | |
else | |
{ | |
return 0xD90007EE; | |
} | |
} | |
return result; | |
} | |
// FFF09544: conditional instruction was optimized away because r0.4!=0 | |
// FFF09560: CONTAINING_RECORD: too small offset 20 for struct 'KSemaphore' | |
//----- (FFF09644) -------------------------------------------------------- | |
Result __fastcall DuplicateHandle(Handle *outHandle, Handle handle) | |
{ | |
KHandleTable *p_handleTable; // r5 | |
KAutoObject *process; // r4 | |
Result v6; // r5 | |
KTypeObj v7; // [sp+0h] [bp-18h] BYREF | |
*outHandle = 0; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
if ( handle == CUR_PROCESS_HANDLE ) | |
{ | |
process = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
} | |
else if ( handle == CUR_THREAD_HANDLE ) | |
{ | |
process = current.clc.current.thread; | |
KAutoObject::IncrementRefcount(current.clc.current.thread); | |
} | |
else | |
{ | |
process = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, handle); | |
} | |
if ( !process ) | |
return 0xD8E007F7; | |
process->GetTypeObj(&v7, process); | |
v6 = KHandleTable::Add(p_handleTable, outHandle, process, v7.typeId); | |
process->DecrementRefcount(process); | |
return v6; | |
} | |
//----- (FFF09720) -------------------------------------------------------- | |
Result __fastcall ReplyAndReceive(s32 *outIdx, Handle *handles, s32 numHandles, Handle replyTargetHandle) | |
{ | |
Result result; // r0 | |
ReplyAndReceiveArgs v6; // [sp+0h] [bp-20h] BYREF | |
*outIdx = 0; | |
if ( !handles ) | |
return 0xD8E007F6; | |
if ( (unsigned int)numHandles <= 0x1FFFFFFF ) | |
result = 0; | |
else | |
result = 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
v6.handles = handles; | |
v6.numHandles = numHandles; | |
v6.replyTargetHandle = replyTargetHandle; | |
v6.res = 0xE7E3FFFF; | |
v6.outIdx = outIdx; | |
if ( CallFuncWithStackAlloc((FuncWithStackAlloc)ReplyAndReceiveImpl, &v6, 4 * numHandles) ) | |
return v6.res; | |
else | |
return 0xD86007F3; | |
} | |
return result; | |
} | |
//----- (FFF0979C) -------------------------------------------------------- | |
Result __fastcall ArbitrateAddress(Handle arbiterHandle, u32 address, ArbitrationType type, s32 value, s64 timeout) | |
{ | |
Result result; // r0 | |
KAutoObject *v8; // r0 | |
KAutoObject *v9; // r4 | |
u8 typeId; // r11 | |
int v11; // r1 | |
KAddressArbiter *v12; // r10 | |
Result v13; // r5 | |
signed int v14; // r5 | |
signed int v15; // r5 | |
signed int v16; // r5 | |
signed int v17; // r5 | |
KTypeObj v18; // [sp+0h] [bp-48h] BYREF | |
KTypeObj v19; // [sp+8h] [bp-40h] BYREF | |
if ( (address & 3) != 0 ) | |
return 0xD8E007F1; | |
v8 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, arbiterHandle); | |
v9 = v8; | |
if ( !v8 ) | |
return 0xD8E007F7; | |
v8->GetTypeObj(&v18, v8); | |
typeId = v18.typeId; | |
v9->GetTypeObj(&v19, v9); | |
v11 = typeId | 0x98; | |
v12 = v11 == v19.typeId ? (KAddressArbiter *)v9 : 0; | |
if ( v11 != v19.typeId ) | |
v9->DecrementRefcount(v9); | |
if ( !v12 ) | |
return 0xD8E007F7; | |
switch ( type ) | |
{ | |
case ARBITRATION_SIGNAL: | |
v13 = KAddressArbiter::Signal(v12, address, value); | |
v12->DecrementRefcount(v12); | |
result = v13; | |
break; | |
case ARBITRATION_WAIT_IF_LESS_THAN: | |
v14 = KAddressArbiter::WaitIfLessThan(v12, current.clc.current.thread, address, value, 0); | |
v12->DecrementRefcount(v12); | |
result = v14; | |
break; | |
case ARBITRATION_DECREMENT_AND_WAIT_IF_LESS_THAN: | |
v15 = KAddressArbiter::WaitIfLessThan(v12, current.clc.current.thread, address, value, 1); | |
v12->DecrementRefcount(v12); | |
result = v15; | |
break; | |
case ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT: | |
v16 = KAddressArbiter::WaitIfLessThanWithTimeout(v12, current.clc.current.thread, address, value, 0, timeout); | |
v12->DecrementRefcount(v12); | |
result = v16; | |
break; | |
case ARBITRATION_DECREMENT_AND_WAIT_IF_LESS_THAN_TIMEOUT: | |
v17 = KAddressArbiter::WaitIfLessThanWithTimeout(v12, current.clc.current.thread, address, value, 1, timeout); | |
v12->DecrementRefcount(v12); | |
result = v17; | |
break; | |
default: | |
v12->DecrementRefcount(v12); | |
result = 0xD8E093ED; | |
break; | |
} | |
return result; | |
} | |
// FFF09864: control flows out of bounds to FFF09868 | |
//----- (FFF099C4) -------------------------------------------------------- | |
Result __fastcall GetResourceLimit(Handle *outReslimit, Handle processHandle) | |
{ | |
KProcess *v3; // r7 | |
KHandleTable *p_handleTable; // r5 | |
KProcess *process; // r4 | |
KAutoObject *v6; // r0 | |
KProcess *v7; // r4 | |
u8 typeId; // r9 | |
KResourceLimit *reslimit; // r7 | |
Result v10; // r5 | |
KTypeObj v12; // [sp+0h] [bp-30h] BYREF | |
KTypeObj v13; // [sp+8h] [bp-28h] BYREF | |
*outReslimit = 0; | |
v3 = 0; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
if ( processHandle == CUR_PROCESS_HANDLE ) | |
{ | |
process = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
} | |
else | |
{ | |
v6 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, processHandle); | |
v7 = (KProcess *)v6; | |
if ( !v6 ) | |
return 0xD9001BF7; | |
v6->GetTypeObj(&v12, v6); | |
typeId = v12.typeId; | |
v7->GetTypeObj(&v13, v7); | |
if ( (typeId | 0xC5) == v13.typeId ) | |
v3 = v7; | |
else | |
v7->DecrementRefcount(v7); | |
process = v3; | |
} | |
if ( !process ) | |
return 0xD9001BF7; | |
reslimit = process->reslimit; | |
if ( reslimit ) | |
{ | |
reslimit->GetTypeObj(&v12, process->reslimit);// possible uaf here | |
v10 = KHandleTable::Add(p_handleTable, outReslimit, reslimit, v12.typeId); | |
process->DecrementRefcount(process); | |
return v10; | |
} | |
else | |
{ | |
process->DecrementRefcount(process); | |
return 0xD8A093F8; | |
} | |
} | |
//----- (FFF09B24) -------------------------------------------------------- | |
Result __fastcall ReleaseSemaphore(s32 *outCount, Handle semaphoreHandle, s32 releaseCount) | |
{ | |
KSemaphore *v3; // r7 | |
Result result; // r0 | |
KAutoObject *v7; // r0 | |
KSemaphore *v8; // r4 | |
u8 typeId; // r9 | |
Result v10; // r5 | |
KTypeObj v11; // [sp+0h] [bp-30h] BYREF | |
KTypeObj v12; // [sp+8h] [bp-28h] BYREF | |
v3 = 0; | |
*outCount = 0; | |
if ( (unsigned int)releaseCount <= 0x7FFFFFFF ) | |
result = 0; | |
else | |
result = 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
v7 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, semaphoreHandle); | |
v8 = (KSemaphore *)v7; | |
if ( !v7 ) | |
return 0xD8E007F7; | |
v7->GetTypeObj(&v11, v7); | |
typeId = v11.typeId; | |
v8->GetTypeObj(&v12, v8); | |
if ( (typeId | 0x2F) == v12.typeId ) | |
v3 = v8; | |
else | |
v8->DecrementRefcount(v8); | |
if ( v3 ) | |
{ | |
v10 = KSemaphore::Release(v3, outCount, releaseCount); | |
v3->DecrementRefcount(v3); | |
return v10; | |
} | |
else | |
{ | |
return 0xD8E007F7; | |
} | |
} | |
return result; | |
} | |
//----- (FFF09C1C) -------------------------------------------------------- | |
Result __fastcall ReplyAndReceive1(s32 *outIdx, Handle *handles, s32 numHandles, Handle replyTargetHandle) | |
{ | |
*outIdx = 0; | |
return -121632780; | |
} | |
//----- (FFF09C30) -------------------------------------------------------- | |
Result __fastcall ReplyAndReceive2(s32 *outIdx, Handle *handles, s32 numHandles, Handle replyTargetHandle) | |
{ | |
*outIdx = 0; | |
return -121632780; | |
} | |
//----- (FFF09C44) -------------------------------------------------------- | |
Result __fastcall ReplyAndReceive3(s32 *outIdx, Handle *handles, s32 numHandles, Handle replyTargetHandle) | |
{ | |
*outIdx = 0; | |
return -121632780; | |
} | |
//----- (FFF09C58) -------------------------------------------------------- | |
Result __fastcall ReplyAndReceive4(s32 *outIdx, Handle *handles, s32 numHandles, Handle replyTargetHandle) | |
{ | |
*outIdx = 0; | |
return -121632780; | |
} | |
//----- (FFF09C6C) -------------------------------------------------------- | |
Result __fastcall CreateMemoryBlock(Handle *outSharedMemHandle, u32 addr, u32 size, u32 ownerPerms, u32 othersPerms) | |
{ | |
Result result; // r0 | |
bool v9; // zf | |
Result v10; // r1 | |
bool v11; // zf | |
bool v12; // zf | |
KProcess *volatile process; // r10 | |
bool v14; // cf | |
u32 v15; // r0 | |
KResourceLimit *reslimit; // r5 | |
bool v17; // r11 | |
KSharedMemory *v18; // r0 | |
KSharedMemory *v19; // r4 | |
Result v20; // r0 | |
Result v21; // r7 | |
bool v22; // zf | |
bool v23; // zf | |
bool v24; // zf | |
Result v25; // r0 | |
Result v26; // r5 | |
KTypeObj v27; // [sp+0h] [bp-40h] BYREF | |
*outSharedMemHandle = 0; | |
result = size << 20; | |
if ( size << 20 ) // check alignment | |
result = 0xE0E01BF2; | |
if ( result < 0 ) | |
return result; | |
result = 0xE0E01BEE; | |
if ( !ownerPerms ) | |
goto LABEL_10; | |
v9 = ownerPerms == KMEMPERM_R; | |
if ( ownerPerms != KMEMPERM_R ) | |
v9 = ownerPerms == KMEMPERM_W; | |
if ( v9 || ownerPerms == KMEMPERM_RW ) | |
LABEL_10: | |
v10 = 0; | |
else | |
v10 = 0xE0E01BEE; | |
if ( v10 < 0 ) | |
return v10; | |
v11 = othersPerms == KMEMPERM_NONE; | |
if ( othersPerms ) | |
v11 = othersPerms == KMEMPERM_R; | |
if ( v11 ) | |
goto LABEL_20; | |
v12 = othersPerms == KMEMPERM_W; | |
if ( othersPerms != KMEMPERM_W ) | |
v12 = othersPerms == KMEMPERM_RW; | |
if ( v12 ) | |
LABEL_20: | |
result = 0; | |
if ( result < 0 ) | |
return result; | |
process = current.clc.current.process; | |
if ( addr ) | |
{ | |
if ( size ) // data + mappable range check | |
// no alignment check on addr? | |
{ | |
v14 = addr >= 0x100000; | |
v15 = addr + size - 1; | |
if ( addr >= 0x100000 ) | |
v14 = v15 >= addr; | |
if ( v14 && v15 < 0x14000000 ) | |
goto LABEL_33; | |
} | |
else if ( addr >= 0x100000 && addr < 0x14000000 ) | |
{ | |
LABEL_33: | |
result = 0; | |
goto LABEL_37; | |
} | |
result = 0xE0E01BF5; | |
LABEL_37: | |
if ( result < 0 ) | |
return result; | |
goto LABEL_38; | |
} | |
if ( (current.clc.current.process->capability.kernelFlags & 0xF00) == MEMOP_REGION_APPLICATION ) | |
return 0xD92007EA; // addr=0 (alloc new linear block) not allowed for applications | |
// | |
// applications can only create transfermem | |
LABEL_38: | |
if ( size << 20 ) | |
{ | |
*outSharedMemHandle = 0; | |
return 0xD8E007F2; | |
} | |
reslimit = current.clc.current.process->reslimit; | |
if ( reslimit ) | |
v17 = KResourceLimit::Reserve(current.clc.current.process->reslimit, RESLIMIT_SHAREDMEMORY, 1); | |
else | |
v17 = 1; | |
if ( !v17 ) | |
return 0xC860180B; | |
v18 = (KSharedMemory *)KSlabHeap::Allocate(&g_sharedMemoryAllocator.slabHeap); | |
v19 = v18; | |
if ( v18 ) | |
{ | |
KSharedMemory::KSharedMemory(v18); | |
KAutoObject::Initialize(v19); | |
} | |
if ( v19 ) | |
{ | |
v20 = KSharedMemory::Initialize(v19, process, addr, size, ownerPerms, othersPerms); | |
if ( v20 < 0 ) | |
{ | |
if ( v20 << 22 == 0xFCC00000 ) // out of mem | |
{ | |
v21 = 0xD86093F3; | |
v19->DecrementRefcount(v19); | |
v22 = reslimit == 0; | |
if ( reslimit ) | |
v22 = !v17; | |
if ( v22 ) | |
return v21; | |
} | |
else | |
{ | |
v21 = v20; | |
v19->DecrementRefcount(v19); | |
v24 = reslimit == 0; | |
if ( reslimit ) | |
v24 = !v17; | |
if ( v24 ) | |
return v21; | |
} | |
KResourceLimit::Release(reslimit, RESLIMIT_SHAREDMEMORY, 1); | |
return v21; | |
} | |
v25 = KObjectAllocator::Register(&g_sharedMemoryAllocator, v19); | |
if ( v25 >= 0 ) | |
{ | |
v19->GetTypeObj(&v27, v19); | |
v25 = KHandleTable::Add(&process->handleTable, outSharedMemHandle, v19, v27.typeId); | |
} | |
v26 = v25; | |
v19->DecrementRefcount(v19); | |
return v26; | |
} | |
else | |
{ | |
v23 = reslimit == 0; | |
if ( reslimit ) | |
v23 = !v17; | |
if ( !v23 ) | |
KResourceLimit::Release(reslimit, RESLIMIT_SHAREDMEMORY, 1); | |
return 0xC8601802; | |
} | |
} | |
// FFF09DF8: conditional instruction was optimized away because r0.4!=0 | |
// FFF09F54: conditional instruction was optimized away because zf.1==1 | |
//----- (FFF09FA4) -------------------------------------------------------- | |
Result __fastcall GetThreadPriority(s32 *outPriority, Handle threadHandle) | |
{ | |
KThread *v3; // r0 | |
*outPriority = 0; | |
v3 = KHandleTable::ConvertToThreadAllowPseudoHandle(¤t.clc.current.process->handleTable, threadHandle); | |
if ( !v3 ) | |
return 0xD9001BF7; | |
*outPriority = v3->dynamicPriority; | |
v3->DecrementRefcount(v3); | |
return 0; | |
} | |
//----- (FFF09FF8) -------------------------------------------------------- | |
Result __fastcall DebugActiveProcess(Handle *outHandle, u32 pid) | |
{ | |
KProcess *reused_var; // r0 | |
bool v4; // zf | |
KProcess *v5; // r4 | |
KHandleTable *p_handleTable; // r8 | |
KDebug *v7; // r0 | |
KDebug *debug; // r5 | |
KDebug *v9; // r0 | |
int v10; // r6 | |
KTypeObj v11; // [sp+0h] [bp-20h] BYREF | |
*outHandle = 0; | |
if ( !g_systemControl.targetSystem.isDevUnit ) | |
return 0xF8C007F4; | |
reused_var = KProcess::OpenById(pid); | |
v5 = reused_var; | |
v4 = reused_var == 0; | |
if ( !reused_var ) | |
reused_var = (KProcess *)0xD9002003; | |
if ( !v4 ) | |
{ | |
if ( (v5->capability.kernelFlags & 1) != 0 || (current.clc.current.process->capability.kernelFlags & 2) != 0 ) | |
{ | |
if ( v5->debug ) | |
{ | |
reused_var->DecrementRefcount(reused_var); | |
return 0xD9002006; | |
} | |
else if ( KProcess::IsTerminated(v5) ) | |
{ | |
v5->DecrementRefcount(v5); | |
return 0xD8A02008; | |
} | |
else | |
{ | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
v7 = (KDebug *)KSlabHeap::Allocate(&g_debugAllocator.slabHeap); | |
debug = v7; | |
if ( v7 ) | |
{ | |
v9 = (KDebug *)KSynchronizationObject::KSynchronizationObject(v7); | |
v9->KSynchronizationObject::KAutoObject::__vftable = &KDebug::vt; | |
v9->KWorkerTask::__vftable = &KDebug::vt_KWorkerTask; | |
v9->next = 0; | |
v9->eventsToFetch.link.next = (KEventInfoLinkedListNode *)&v9->eventsToFetch.link; | |
v9->eventsToFetch.count = 0; | |
v9->eventsToFetch.link.prev = (KEventInfoLinkedListNode *)&v9->eventsToFetch.link; | |
v9->eventsToContinue.link.next = (KEventInfoLinkedListNode *)&v9->eventsToContinue.link; | |
v9->eventsToContinue.count = 0; | |
v9->eventsToContinue.link.prev = (KEventInfoLinkedListNode *)&v9->eventsToContinue.link; | |
v9->debugThreads.count = 0; | |
v9->debugThreads.link.next = 0; | |
v9->debugThreads.link.next = (KDebugThreadLinkedListNode *)&v9->debugThreads.link; | |
v9->debugThreads.link.prev = 0; | |
v9->debugThreads.link.prev = (KDebugThreadLinkedListNode *)&v9->debugThreads.link; | |
v9->orderedThreadListForBreak.link.next = (KThreadLinkedListNode *)&v9->orderedThreadListForBreak.link; | |
v9->orderedThreadListForBreak.count = 0; | |
v9->orderedThreadListForBreak.link.prev = (KThreadLinkedListNode *)&v9->orderedThreadListForBreak.link; | |
v9->lock.lockingThread = 0; | |
v9->lock.lockCount = 0; | |
KAutoObject::Initialize(debug); | |
} | |
if ( debug ) | |
{ | |
KDebug::Intialize(debug, v5); | |
v10 = KObjectAllocator::Register(&g_debugAllocator, debug); | |
if ( v10 >= 0 ) | |
{ | |
KDebug::Attach(debug, v5); | |
debug->GetTypeObj(&v11, debug); | |
v10 = KHandleTable::Add(p_handleTable, outHandle, debug, v11.typeId); | |
} | |
debug->DecrementRefcount(debug); | |
v5->DecrementRefcount(v5); | |
return v10; | |
} | |
else | |
{ | |
v5->DecrementRefcount(v5); | |
return 0xD86007F3; | |
} | |
} | |
} | |
else | |
{ | |
reused_var->DecrementRefcount(reused_var); | |
return 0xD9002005; | |
} | |
} | |
return (Result)reused_var; | |
} | |
// FFF0A104: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF0A25C) -------------------------------------------------------- | |
Result __fastcall QueryProcessMemory(MemoryInfo *outMemInfo, u32 *outPgInfo, Handle processHandle, u32 addr) | |
{ | |
KProcess *v4; // r5 | |
Result result; // r0 | |
KProcess *volatile process; // r4 | |
KAutoObject *v10; // r0 | |
KAutoObject *v11; // r4 | |
u8 typeId; // r10 | |
int v13; // r5 | |
u32 size; // r0 | |
char perms; // r2 | |
unsigned __int8 state; // r3 | |
KMemoryInfo v17; // [sp+0h] [bp-40h] BYREF | |
KTypeObj v18; // [sp+10h] [bp-30h] BYREF | |
KTypeObj v19; // [sp+18h] [bp-28h] BYREF | |
v4 = 0; | |
memset(&v17, 0, sizeof(v17)); | |
outMemInfo->baseAddress = 0; | |
outMemInfo->size = 0; | |
outMemInfo->perms = 0; | |
outMemInfo->state = 0; | |
if ( addr < 0x40000000 ) | |
result = 0; | |
else | |
result = 0xE0E01BF5; | |
*outPgInfo = 0; | |
if ( result < 0 ) | |
return result; | |
if ( processHandle == CUR_PROCESS_HANDLE ) | |
{ | |
process = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
} | |
else | |
{ | |
v10 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, processHandle); | |
v11 = v10; | |
if ( !v10 ) | |
return 0xD9001BF7; | |
v10->GetTypeObj(&v18, v10); | |
typeId = v18.typeId; | |
v11->GetTypeObj(&v19, v11); | |
if ( (typeId | 0xC5) == v19.typeId ) | |
v4 = (KProcess *)v11; | |
else | |
v11->DecrementRefcount(v11); | |
process = v4; | |
} | |
if ( !process ) | |
return 0xD9001BF7; | |
v13 = KPageTable::QueryInfo(&process->pgTable, &v17, outPgInfo, addr); | |
if ( v13 >= 0 ) | |
{ | |
size = v17.size; | |
perms = v17.perms; | |
state = v17.state; | |
outMemInfo->baseAddress = v17.baseAddress; | |
outMemInfo->size = size; | |
outMemInfo->perms = perms & 3; | |
outMemInfo->state = state; | |
v13 = 0; | |
outMemInfo->perms = v17.perms & 7; | |
} | |
process->DecrementRefcount(process); | |
return v13; | |
} | |
//----- (FFF0A3E8) -------------------------------------------------------- | |
Result __fastcall CreateResourceLimit(Handle *outReslimitHandle) | |
{ | |
KHandleTable *p_handleTable; // r6 | |
KResourceLimit *v3; // r0 | |
KResourceLimit *v4; // r4 | |
KResourceLimit *v5; // r0 | |
int v7; // r7 | |
KTypeObj v8; // [sp+0h] [bp-20h] BYREF | |
*outReslimitHandle = 0; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
v3 = (KResourceLimit *)KSlabHeap::Allocate(&g_resourceLimitAllocator.slabHeap); | |
v4 = v3; | |
if ( v3 ) | |
{ | |
v5 = (KResourceLimit *)KAutoObject::KAutoObject(v3); | |
v5->__vftable = &KResourceLimit::vt; | |
v5->mutex.lockingThread = 0; | |
v5->mutex.numWaiters = 0; | |
v5->mutex.ticketCount = 0; | |
v5->timeLimit.category = KCPUTIMELIMIT_CATEGORY_APPLICATION; | |
v5->timeLimit.currentWdTicksElapsed = 0; | |
v5->timeLimit.previousWdCounterValue = 0; | |
v5->timeLimit.limitTick = 0; | |
KAutoObject::Initialize(v4); | |
} | |
if ( !v4 ) | |
return 0xC8601801; | |
KResourceLimit::Initialize(v4); | |
v7 = KObjectAllocator::Register(&g_resourceLimitAllocator, v4); | |
if ( v7 >= 0 ) | |
{ | |
v4->GetTypeObj(&v8, v4); | |
v7 = KHandleTable::Add(p_handleTable, outReslimitHandle, v4, v8.typeId); | |
} | |
v4->DecrementRefcount(v4); | |
return v7; | |
} | |
// FFF0A42C: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF0A4F8) -------------------------------------------------------- | |
Result __fastcall CreateSessionToPort(Handle *outClientSessionHandle, Handle clientPortHandle) | |
{ | |
KHandleTable *p_handleTable; // r5 | |
KAutoObject *v4; // r0 | |
KAutoObject *v5; // r4 | |
u8 typeId; // r9 | |
int v7; // r1 | |
KClientPort *clientPort; // r7 | |
KClientPort *v9; // r4 | |
Result result; // r0 | |
KClientSession *v11; // r7 | |
Result v12; // r5 | |
KClientSession *clientSession; // [sp+0h] [bp-38h] BYREF | |
KTypeObj v14; // [sp+8h] [bp-30h] BYREF | |
KTypeObj v15; // [sp+10h] [bp-28h] BYREF | |
*outClientSessionHandle = 0; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
v4 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, clientPortHandle); | |
v5 = v4; | |
if ( !v4 ) | |
return 0xD8E007F7; | |
v4->GetTypeObj(&v14, v4); | |
typeId = v14.typeId; | |
v5->GetTypeObj(&v15, v5); | |
v7 = typeId | 0x65; | |
clientPort = v7 == v15.typeId ? (KClientPort *)v5 : 0; | |
if ( v7 != v15.typeId ) | |
v5->DecrementRefcount(v5); | |
v9 = clientPort; | |
if ( !clientPort ) | |
return 0xD8E007F7; | |
result = KClientPort::CreateSession(clientPort, &clientSession); | |
if ( result >= 0 ) | |
{ | |
v11 = clientSession; | |
clientSession->GetTypeObj(&v14, clientSession); | |
v12 = KHandleTable::Add(p_handleTable, outClientSessionHandle, v11, v14.typeId); | |
clientSession->DecrementRefcount(clientSession); | |
v9->DecrementRefcount(v9); | |
return v12; | |
} | |
return result; | |
} | |
//----- (FFF0A630) -------------------------------------------------------- | |
Result __fastcall GetDebugThreadParam(s64 *out1, s32 *out2, Handle debugHandle, u32 tid, DebugThreadParameter param) | |
{ | |
KDebug *v7; // r0 | |
KDebug *v9; // r4 | |
KProcess *process; // r8 | |
KThread *v11; // r0 | |
Result v12; // r5 | |
int var; // r1 | |
*out1 = 0LL; | |
*out2 = 0; | |
v7 = KHandleTable::ConvertCurProcHandleToDebug(debugHandle); | |
if ( !v7 ) | |
return 0xD9002002; | |
v9 = v7; | |
process = v7->process; | |
v11 = KThread::FindById(tid); | |
v12 = -654303228; | |
if ( v11 ) | |
{ | |
var = (int)v11->owner; | |
if ( (KProcess *)var == process ) | |
{ | |
if ( param ) | |
{ | |
if ( param == DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW ) | |
{ | |
var = v11->schedulingMask & 0xF; | |
} | |
else if ( param == DBGTHREAD_PARAMETER_CPU_IDEAL ) | |
{ | |
var = v11->idealProcessor; | |
} | |
else | |
{ | |
if ( param == DBGTHREAD_PARAMETER_CPU_CREATOR ) | |
var = v11->coreId; | |
else | |
v12 = 0xF8C007F4; | |
if ( param != DBGTHREAD_PARAMETER_CPU_CREATOR ) | |
goto LABEL_5; | |
} | |
} | |
else | |
{ | |
var = v11->basePriority; | |
} | |
v12 = 0; | |
*out2 = var; | |
} | |
LABEL_5: | |
v11->DecrementRefcount(v11); | |
} | |
v9->DecrementRefcount(v9); | |
return v12; | |
} | |
//----- (FFF0A700) -------------------------------------------------------- | |
Result __fastcall CreateAddressArbiter(Handle *outArbiterHandle) | |
{ | |
KProcess *process; // r10 | |
KHandleTable *p_handleTable; // r11 | |
KResourceLimit *reslimit; // r7 | |
bool v5; // r8 | |
KAddressArbiter *v7; // r0 | |
KAddressArbiter *v8; // r4 | |
KAddressArbiter *v9; // r0 | |
int v10; // r7 | |
bool v11; // zf | |
KTypeObj v12; // [sp+0h] [bp-30h] BYREF | |
*outArbiterHandle = 0; | |
process = current.clc.current.process; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
reslimit = current.clc.current.process->reslimit; | |
if ( reslimit ) | |
v5 = KResourceLimit::Reserve(current.clc.current.process->reslimit, RESLIMIT_ADDRESSARBITER, 1); | |
else | |
v5 = 1; | |
if ( !v5 ) | |
return 0xC8601833; | |
v7 = (KAddressArbiter *)KSlabHeap::Allocate(&g_addressArbiterAllocator.slabHeap); | |
v8 = v7; | |
if ( v7 ) | |
{ | |
v9 = (KAddressArbiter *)KAutoObject::KAutoObject(v7); | |
v9->__vftable = &KAddressArbiter::vt; | |
v9->waitList.link.prev = 0; | |
v9->waitList.link.next = 0; | |
KAutoObject::Initialize(v8); | |
} | |
if ( v8 ) | |
{ | |
KAddressArbiter::Initialize(v8, process); | |
v10 = KObjectAllocator::Register(&g_addressArbiterAllocator, v8); | |
if ( v10 >= 0 ) | |
{ | |
v8->GetTypeObj(&v12, v8); | |
v10 = KHandleTable::Add(p_handleTable, outArbiterHandle, v8, v12.typeId); | |
} | |
v8->DecrementRefcount(v8); | |
return v10; | |
} | |
else | |
{ | |
v11 = reslimit == 0; | |
if ( reslimit ) | |
v11 = !v5; | |
if ( !v11 ) | |
KResourceLimit::Release(reslimit, RESLIMIT_ADDRESSARBITER, 1); | |
return 0xC8601801; | |
} | |
} | |
// FFF0A790: conditional instruction was optimized away because r0.4!=0 | |
// FFF0A828: conditional instruction was optimized away because zf.1==1 | |
//----- (FFF0A894) -------------------------------------------------------- | |
Result __fastcall GetProcessIdOfThread(u32 *outPid, Handle threadHandle) | |
{ | |
KThread *v3; // r0 | |
KThread *v5; // r4 | |
*outPid = 0; | |
v3 = KHandleTable::ConvertToThreadAllowPseudoHandle(¤t.clc.current.process->handleTable, threadHandle); | |
if ( !v3 ) | |
return 0xD9001BF7; | |
v5 = v3; | |
*outPid = KThread::GetProcessId(v3); | |
v5->DecrementRefcount(v5); | |
return 0; | |
} | |
//----- (FFF0A8F0) -------------------------------------------------------- | |
Result __fastcall WaitSynchronizationN(s32 *outIdx, Handle *handles, s32 numHandles, bool waitAll, s64 timeout) | |
{ | |
Result result; // r0 | |
WaitSynchronizationNArgs v7; // [sp+0h] [bp-30h] BYREF | |
*outIdx = 0; | |
if ( !handles ) | |
return 0xD8E007F6; | |
if ( (unsigned int)numHandles <= 0x1FFFFFFF ) | |
result = 0; | |
else | |
result = 0xE0E01BFD; | |
if ( result >= 0 ) | |
{ | |
if ( timeout >= 0 || timeout == -1 ) | |
{ | |
v7.handles = handles; | |
v7.res = 0xE7E3FFFF; | |
v7.numHandles = numHandles; | |
v7.outIdx = outIdx; | |
v7.waitAll = waitAll; | |
v7.timeout = timeout; | |
if ( CallFuncWithStackAlloc((FuncWithStackAlloc)WaitSynchronizationNImpl, &v7, 4 * numHandles) ) | |
return v7.res; | |
else | |
return 0xD86007F3; | |
} | |
else | |
{ | |
return 0xD8E007FD; | |
} | |
} | |
return result; | |
} | |
//----- (FFF0A9A8) -------------------------------------------------------- | |
Result __fastcall GetThreadIdealProcessor(s32 *outIdealProcessor, Handle threadHandle) | |
{ | |
KThread *v3; // r0 | |
*outIdealProcessor = 0; | |
v3 = KHandleTable::ConvertToThreadAllowPseudoHandle(¤t.clc.current.process->handleTable, threadHandle); | |
if ( !v3 ) | |
return 0xD9001BF7; | |
*outIdealProcessor = v3->idealProcessor; | |
v3->DecrementRefcount(v3); | |
return 0; | |
} | |
//----- (FFF0A9F8) -------------------------------------------------------- | |
Result __fastcall QueryDebugProcessMemory(MemoryInfo *outMemInfo, u32 *outPgInfo, Handle debugHandle, u32 addr) | |
{ | |
KDebug *v7; // r0 | |
KDebug *v8; // r4 | |
Result result; // r0 | |
int res; // r5 | |
outMemInfo->baseAddress = 0; | |
outMemInfo->size = 0; | |
outMemInfo->perms = 0; | |
outMemInfo->state = 0; | |
*outPgInfo = 0; | |
v7 = KHandleTable::ConvertCurProcHandleToDebug(debugHandle); | |
v8 = v7; | |
if ( !v7 ) | |
return 0xD9002002; | |
if ( KDebug::IsProcessTerminated(v7) ) | |
{ | |
v8->DecrementRefcount(v8); | |
return 0xD8A02008; | |
} | |
else | |
{ | |
res = KDebug::QueryProcessMemory(v8, outMemInfo, outPgInfo, addr); | |
v8->DecrementRefcount(v8); | |
result = res; | |
if ( res < 0 && (res & 0x3FF) == 0x3F5 ) | |
return 0xE0E0200A; | |
} | |
return result; | |
} | |
//----- (FFF0AAB0) -------------------------------------------------------- | |
Result __fastcall ControlProcessMemory(Handle processHandle, u32 addr0, u32 addr1, u32 size, u32 op, u32 perms) | |
{ | |
Result result; // r0 | |
bool v11; // zf | |
Result v12; // r1 | |
KAutoObject *v13; // r0 | |
KAutoObject *v14; // r11 | |
int v15; // r1 | |
KProcess *proc; // r4 | |
KProcessPageTable *pgTable; // r0 | |
u32 v18; // r2 | |
u32 addr; // r1 | |
Result Alias; // r0 | |
Result v21; // r5 | |
KMemoryState expectedStateSrc; // [sp+0h] [bp-40h] BYREF | |
KMemoryPermission minPerms; // [sp+4h] [bp-3Ch] | |
KMemoryState stateDst; // [sp+8h] [bp-38h] BYREF | |
KMemoryState newPerms; // [sp+Ch] [bp-34h] | |
KMemoryState newStateDst; // [sp+10h] [bp-30h] | |
KMemoryUpdateFlags v27; // [sp+18h] [bp-28h] | |
result = 0xD8E007F6; | |
if ( addr0 ) | |
{ | |
v11 = op == MEMOP_MAP; | |
if ( op != MEMOP_MAP ) | |
v11 = op == MEMOP_UNMAP; | |
if ( !v11 || addr1 ) | |
{ | |
result = 0xE0E01BF1; // check if addrs are aligned and non-null | |
v12 = addr0 << 20; | |
if ( addr0 << 20 ) | |
v12 = 0xE0E01BF1; | |
if ( v12 < 0 ) | |
return v12; | |
if ( !(addr1 << 20) ) | |
result = 0; | |
if ( result >= 0 ) | |
{ | |
result = size << 20; | |
if ( size << 20 ) | |
result = 0xE0E01BF2; | |
if ( result >= 0 ) | |
{ | |
v13 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, processHandle); | |
v14 = v13; | |
if ( !v13 ) | |
return 0xD9001BF7; | |
v13->GetTypeObj((KTypeObj *)&stateDst, v13); | |
newStateDst = newPerms; | |
v14->GetTypeObj((KTypeObj *)&expectedStateSrc, v14); | |
v15 = (unsigned __int8)newStateDst | 0xC5; | |
proc = v15 == (unsigned __int8)minPerms ? (KProcess *)v14 : 0; | |
if ( v15 != (unsigned __int8)minPerms ) | |
v14->DecrementRefcount(v14); | |
if ( !proc ) | |
return 0xD9001BF7; | |
pgTable = &proc->pgTable; | |
v18 = size >> 12; | |
switch ( op ) | |
{ | |
case MEMOP_MAP: | |
if ( addr0 != addr1 ) | |
{ | |
Alias = KPageTable::CreateAlias( | |
pgTable, | |
addr1, | |
addr0, | |
size >> 12, | |
KMEMSTATE_PRIVATE_DATA, | |
KMEMPERM_RW, | |
KMEMSTATE_LOCKED, | |
KMEMPERM_NONE, | |
KMEMSTATE_ALIAS_CODE, | |
(KMemoryPermission)(perms | KMEMPERM_KRW)); | |
goto LABEL_37; | |
} | |
newPerms = perms | KMEMPERM_KRW; | |
expectedStateSrc = KMEMSTATE_PRIVATE_DATA; | |
minPerms = KMEMPERM_RW; | |
stateDst = KMEMSTATE_PRIVATE_ALIAS_CODE; | |
addr = addr1; | |
break; | |
case MEMOP_UNMAP: | |
if ( addr0 != addr1 ) | |
{ | |
Alias = KPageTable::DestroyAlias( | |
pgTable, | |
addr1, | |
addr0, | |
size >> 12, | |
KMEMSTATE_LOCKED, | |
KMEMPERM_NONE, | |
KMEMSTATE_ALIAS_CODE, | |
KMEMPERM_NONE, | |
KMEMSTATE_PRIVATE_DATA, | |
(KMemoryPermission)(perms | KMEMPERM_KRW), | |
v27); | |
goto LABEL_37; | |
} | |
minPerms = KMEMPERM_NONE; | |
expectedStateSrc = KMEMSTATE_PRIVATE_ALIAS_CODE; | |
stateDst = KMEMSTATE_PRIVATE_DATA; | |
newPerms = perms | KMEMPERM_KRW; | |
addr = addr0; | |
break; | |
case MEMOP_PROT: | |
Alias = KPageTable::Operate( | |
pgTable, | |
addr0, | |
v18, | |
0, | |
MEMSTATE_FREE, | |
(KMemoryPermission)(perms | KMEMPERM_KRW), | |
KMEMUPDATE_PERMS, | |
0x300u); | |
LABEL_37: | |
v21 = Alias; | |
proc->DecrementRefcount(proc); | |
return v21; | |
default: | |
proc->DecrementRefcount(proc); | |
return 0xF8C007F4; | |
} | |
Alias = KPageTable::CheckAndUpdateAddrRangeMaskedStateAndPerms( | |
pgTable, | |
addr, | |
v18, | |
KMEMSTATE_FLAGS_ANY, | |
expectedStateSrc, | |
minPerms, | |
stateDst, | |
(KMemoryPermission)newPerms);// map/unmap: change permissions and state | |
goto LABEL_37; | |
} | |
} | |
} | |
} | |
return result; | |
} | |
//----- (FFF0AD40) -------------------------------------------------------- | |
Result __fastcall GetProcessIdealProcessor(s32 *outIdealProcessor, Handle processHandle) | |
{ | |
KProcess *v3; // r0 | |
*outIdealProcessor = 0; | |
v3 = KHandleTable::ConvertToProcessAllowPseudoHandle(¤t.clc.current.process->handleTable, processHandle); | |
if ( !v3 ) | |
return 0xD9001BF7; | |
*outIdealProcessor = v3->idealProcessor; | |
v3->DecrementRefcount(v3); | |
return 0; | |
} | |
//----- (FFF0AD90) -------------------------------------------------------- | |
Result __fastcall ControlPerformanceCounter(s64 *out, PerformanceCounterOperation op, u32 param1, u64 param2) | |
{ | |
unsigned int pid; // r4 | |
Result result; // r0 | |
unsigned int v7; // r1 | |
KProcess *proc; // r0 | |
u32 v9; // r1 | |
unsigned int v10; // r3 | |
s64 CounterValue; // r0 | |
*out = 0LL; | |
pid = current.clc.current.process->pid; | |
if ( op == PERFCOUNTEROP_ENABLE ) | |
{ | |
LABEL_5: | |
while ( 1 ) | |
{ | |
v7 = __ldrex(&g_perfCounterMgrExclusivePid); | |
if ( v7 != -1 ) | |
break; | |
if ( !__strex(pid, &g_perfCounterMgrExclusivePid) ) | |
{ | |
LABEL_9: | |
if ( v7 == -1 ) | |
{ | |
KPerformanceCounterManager::Enable(&g_perfCounterMgr); | |
return 0; | |
} | |
proc = KProcess::OpenById(g_perfCounterMgrExclusivePid); | |
if ( proc ) | |
{ | |
proc->DecrementRefcount(proc); | |
return 0xC8401FF0; | |
} | |
v9 = g_perfCounterMgrExclusivePid; | |
while ( 1 ) | |
{ | |
v10 = __ldrex(&g_perfCounterMgrExclusivePid); | |
if ( v10 != v9 ) | |
break; | |
if ( !__strex(0xFFFFFFFF, &g_perfCounterMgrExclusivePid) ) | |
goto LABEL_5; | |
} | |
__clrex(); | |
} | |
} | |
__clrex(); | |
goto LABEL_9; | |
} | |
if ( g_perfCounterMgrExclusivePid != pid ) | |
return 0xD8A01FEA; | |
switch ( op ) | |
{ | |
case PERFCOUNTEROP_DISABLE: | |
KPerformanceCounterManager::Disable(); | |
do | |
__ldrex(&g_perfCounterMgrExclusivePid); | |
while ( __strex(-1u, &g_perfCounterMgrExclusivePid) ); | |
goto LABEL_29; | |
case PERFCOUNTEROP_GET_VALUE: | |
CounterValue = KPerformanceCounterManager::GetCounterValue(&g_perfCounterMgr, (PerformanceCounterName)param1); | |
goto LABEL_24; | |
case PERFCOUNTEROP_SET_VALUE: | |
KPerformanceCounterManager::SetCounterValue(&g_perfCounterMgr, (PerformanceCounterName)param1, param2); | |
goto LABEL_29; | |
case PERFCOUNTEROP_GET_OVERFLOW_FLAGS: | |
CounterValue = KPerformanceCounterManager::GetOverflowFlags(); | |
LABEL_24: | |
*out = CounterValue; | |
goto LABEL_29; | |
case PERFCOUNTEROP_RESET: | |
KPerformanceCounterManager::ResetCounters(&g_perfCounterMgr, param1, param2); | |
goto LABEL_29; | |
case PERFCOUNTEROP_GET_EVENT: | |
*out = (unsigned int)KPerformanceCounterManager::GetEvent(&g_perfCounterMgr, (PerformanceCounterName)param1); | |
goto LABEL_29; | |
case PERFCOUNTEROP_SET_EVENT: | |
KPerformanceCounterManager::SetEvent( | |
&g_perfCounterMgr, | |
(PerformanceCounterName)param1, | |
(PerformanceCounterEvent)param2); | |
goto LABEL_29; | |
case PERFCOUNTEROP_SET_VIRTUAL_COUNTER_ENABLED: | |
KPerformanceCounterManager::SetVirtualCounterEnabled(&g_perfCounterMgr, param1 != 0); | |
LABEL_29: | |
result = 0; | |
break; | |
default: | |
result = 0xF8C007F4; | |
break; | |
} | |
return result; | |
} | |
// FFF0ADE0: control flows out of bounds to FFF0ADE4 | |
//----- (FFF0AF94) -------------------------------------------------------- | |
Result __fastcall KCacheOperator::OperateOnProcessCache(KCacheOperator *this, Handle processHandle, u32 addr, u32 size) | |
{ | |
KCacheOperator *v5; // r10 | |
bool v8; // cc | |
KProcess *proc; // r11 | |
KAutoObject *v10; // r0 | |
KProcess *v11; // r11 | |
u8 typeId; // r8 | |
int v13; // r1 | |
KProcess *v14; // r4 | |
KLightMutex *p_mutex; // r4 | |
unsigned int v16; // r2 | |
unsigned int v17; // r1 | |
bool v18; // zf | |
unsigned int v19; // r2 | |
KLightMutex *v20; // [sp+0h] [bp-78h] | |
u32 totalSz; // [sp+4h] [bp-74h] | |
KTranslationTableTraversalContext v22; // [sp+8h] [bp-70h] BYREF | |
KTranslationTableIterator it; // [sp+10h] [bp-68h] BYREF | |
KTranslationTableIterator it2; // [sp+18h] [bp-60h] | |
int v25; // [sp+20h] [bp-58h] | |
KTypeObj v26; // [sp+28h] [bp-50h] BYREF | |
KTypeObj v27; // [sp+30h] [bp-48h] BYREF | |
v5 = this; | |
if ( !addr ) | |
this = (KCacheOperator *)0xD8E007F6; | |
if ( !addr ) | |
return (Result)this; | |
if ( addr >= 0x40000000 ) // very loose address check | |
return 0xE0E01BF5; | |
v8 = size > 0x40000000; | |
if ( size <= 0x40000000 ) | |
v8 = addr + size > 0x40000000; | |
if ( v8 ) | |
return 0xE0E01BF5; | |
if ( v5->GetThreshold(v5) <= size ) | |
{ | |
v5->DoEntireOperation(v5); // notice it ignores the address past the first few checks | |
return 0; | |
} | |
if ( processHandle == CUR_PROCESS_HANDLE ) | |
{ | |
proc = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
} | |
else | |
{ | |
v10 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, processHandle); | |
v11 = (KProcess *)v10; | |
if ( !v10 ) | |
return 0xD9001BF7; | |
v10->GetTypeObj(&v27, v10); | |
typeId = v27.typeId; | |
v11->GetTypeObj(&v26, v11); | |
v13 = typeId | 0xC5; | |
if ( v13 == v26.typeId ) | |
v14 = v11; | |
else | |
v14 = 0; | |
if ( v13 != v26.typeId ) | |
v11->DecrementRefcount(v11); | |
proc = v14; | |
} | |
if ( !proc ) | |
return 0xD9001BF7; | |
p_mutex = &proc->pgTable.mutex; | |
v25 = 0; | |
v20 = &proc->pgTable.mutex; | |
totalSz = size; | |
v16 = __ldrex((unsigned int *)&proc->pgTable); | |
if ( v16 ) | |
{ | |
__strex(v16, (unsigned int *)p_mutex); | |
} | |
else if ( !__strex((unsigned int)current.clc.current.thread, (unsigned int *)p_mutex) ) | |
{ | |
goto LABEL_25; | |
} | |
KLightMutex::LockImpl(&proc->pgTable.mutex); | |
LABEL_25: | |
__mcr(15, 0, 0, 7, 10, 5); | |
KTranslationTableIterator::CreateFromEntry(&proc->pgTable.L1Table, &it, &v22, addr); | |
__mcr(15, 0, 0, 7, 10, 5); | |
p_mutex->lockingThread = 0; | |
if ( proc->pgTable.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&proc->pgTable.mutex); | |
it2.size = 0; | |
if ( it.pa ) | |
it.size -= (it.size - 1) & addr; // misaligned addr | |
else | |
totalSz = 0; // if addr is invalid don't do anything | |
LABEL_30: | |
v25 += it2.size; | |
for ( it2 = it; ; it2.size += it.size ) | |
{ | |
if ( it2.size + v25 >= totalSz ) | |
{ | |
if ( v25 == totalSz ) | |
goto LABEL_51; | |
it2.size = totalSz - v25; | |
LABEL_54: | |
v5->DoRangeOperation(v5, it2.pa + 0xC0000000, it2.size);// operate on each chunk | |
goto LABEL_30; | |
} | |
v17 = __ldrex((unsigned int *)v20); | |
v18 = v17 == 0; | |
if ( v17 ) | |
v19 = __strex(v17, (unsigned int *)v20); | |
else | |
v19 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)v20); | |
if ( !v17 ) | |
v18 = v19 == 0; | |
if ( !v18 ) | |
KLightMutex::LockImpl(v20); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KTranslationTableIterator::Advance(&proc->pgTable.L1Table, &it, &v22); | |
__mcr(15, 0, 0, 7, 10, 5); | |
v20->lockingThread = 0; | |
if ( proc->pgTable.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v20); | |
if ( !it.pa ) | |
break; | |
if ( it2.pa + it2.size != it.pa ) | |
goto LABEL_54; | |
} | |
totalSz = 0; | |
v25 = 0; | |
LABEL_51: | |
if ( totalSz ) | |
{ | |
proc->DecrementRefcount(proc); // path for invalid addr | |
return 0; | |
} | |
proc->DecrementRefcount(proc); | |
return 0xE0E01BF5; | |
} | |
//----- (FFF0B2BC) -------------------------------------------------------- | |
Result __fastcall KProcessPageTable::UnmapProcessMemory(KProcessPageTable *this, u32 addr, u32 numPages) | |
{ | |
u32 v3; // r5 | |
u32 dstPos; // r4 | |
Result result; // r0 | |
KMemoryInfo outMemoryInfo; // [sp+10h] [bp-30h] BYREF | |
u32 pageInfo; // [sp+20h] [bp-20h] BYREF | |
v3 = addr + (numPages << 12); | |
for ( dstPos = addr; ; dstPos = outMemoryInfo.baseAddress + outMemoryInfo.size ) | |
{ | |
result = KPageTable::QueryInfo(this, &outMemoryInfo, &pageInfo, dstPos); | |
if ( result < 0 || outMemoryInfo.baseAddress + outMemoryInfo.size > v3 ) | |
break; | |
if ( *(_QWORD *)&outMemoryInfo.perms == 0x58060000001BLL// shared memstate, krw_rw | |
&& KPageTable::Operate( | |
this, | |
dstPos, | |
outMemoryInfo.size >> 12, | |
0, | |
MEMSTATE_FREE, | |
KMEMPERM_NONE, | |
KMEMUPDATE_NONE, | |
0) < 0 ) | |
{ | |
kernelpanic(); | |
} | |
} | |
return result; | |
} | |
//----- (FFF0B368) -------------------------------------------------------- | |
Result __fastcall KProcessPageTable::MapProcessMemory( | |
KProcessPageTable *dstPgTbl, | |
KPageTable *srcPgTbl, | |
u32 dstAddr, | |
u32 srcAddr, | |
u32 numPages) | |
{ | |
Result result; // r0 | |
u32 pos; // r4 | |
int v10; // r1 | |
u32 v11; // r6 | |
u32 dstPos; // r4 | |
Result v13; // r0 | |
KMemoryInfo info; // [sp+10h] [bp-50h] BYREF | |
u32 endDstAddr; // [sp+20h] [bp-40h] | |
u32 pageInfo[3]; // [sp+24h] [bp-3Ch] BYREF | |
pageInfo[2] = (u32)dstPgTbl; | |
result = KPageTable::CheckMemoryBlockAttributes(dstPgTbl, dstAddr, numPages << 12, MEMSTATE_FREE, KMEMPERM_NONE); | |
if ( result >= 0 ) | |
{ | |
endDstAddr = dstAddr + (numPages << 12); | |
while ( 1 ) | |
{ | |
for ( pos = 0; ; pos += info.size ) | |
{ | |
v10 = KPageTable::QueryInfo(srcPgTbl, &info, pageInfo, srcAddr + pos); | |
if ( v10 < 0 ) | |
break; | |
if ( info.baseAddress == srcAddr + pos ) | |
{ | |
if ( info.size + pos > numPages << 12 ) | |
break; | |
if ( (info.state & (unsigned __int16)KMEMSTATE_FLAG_CODE_ALLOWED) != 0 ) | |
{ | |
v10 = KPageTable::RemapMemoryInterprocess(// only text/rodata/data/bss/heap | |
// | |
// why.....? | |
dstPgTbl, | |
srcPgTbl, | |
dstAddr + pos, | |
srcAddr + pos, | |
info.size >> 12, | |
KMEMSTATE_SHARED, | |
KMEMPERM_KRW_RW); | |
if ( v10 < 0 ) | |
break; | |
} | |
} | |
else | |
{ | |
if ( pos ) | |
{ | |
v10 = 0xD940060E; | |
break; | |
} | |
pos = info.baseAddress - srcAddr; | |
} | |
} | |
result = v10; | |
if ( v10 >= 0 ) | |
break; | |
if ( v10 != 0xD940060E ) | |
kernelpanic(); | |
v11 = endDstAddr; | |
for ( dstPos = dstAddr; ; dstPos = info.baseAddress + info.size ) | |
{ | |
v13 = KPageTable::QueryInfo(dstPgTbl, &info, pageInfo, dstPos); | |
if ( v13 < 0 || info.baseAddress + info.size > v11 ) | |
break; | |
if ( *(_QWORD *)&info.perms == 0x58060000001BLL | |
&& KPageTable::Operate(dstPgTbl, dstPos, info.size >> 12, 0, MEMSTATE_FREE, KMEMPERM_NONE, KMEMUPDATE_NONE, 0) < 0 ) | |
{ | |
kernelpanic(); // Unmap KRW_RW shared memory if it's already there in the destination process | |
// | |
// This is inlined UnmapProcessMemory | |
} | |
} | |
if ( v13 < 0 ) | |
kernelpanic(); | |
} | |
} | |
return result; | |
} | |
//----- (FFF0B530) -------------------------------------------------------- | |
void __fastcall SetResourceLimitLimitValues(SetResourceLimitLimitValuesArgs *args, ResourceLimitKvPair *pairs) | |
{ | |
s32 v4; // r6 | |
Result v5; // r4 | |
Result v6; // r9 | |
ResourceLimitKvPair *v7; // r4 | |
Result v8; // r0 | |
int v9; // r0 | |
Result v10; // r0 | |
KResourceLimit *v11; // r6 | |
s32 i; // r4 | |
ResourceLimitKvPair *v13; // r3 | |
u32 value_high; // r0 | |
unsigned int v15; // [sp+0h] [bp-30h] BYREF | |
int dst; // [sp+8h] [bp-28h] BYREF | |
int v17; // [sp+Ch] [bp-24h] | |
v4 = 0; | |
if ( args->count <= 0 ) | |
{ | |
LABEL_19: | |
v11 = KHandleTable::ConvertToResourceLimit(¤t.clc.current.process->handleTable, args->reslimitHandle); | |
if ( v11 ) | |
{ | |
for ( i = 0; args->count > i; ++i ) | |
{ | |
v13 = &pairs[i]; | |
if ( v13->name == RESLIMIT_COMMIT ) | |
{ | |
value_high = HIDWORD(v13->value); | |
if ( value_high ) | |
g_kernelSharedConfigPagePtr->appMemAlloc = value_high; | |
} | |
KResourceLimit::SetLimitValue(v11, v13->name, v13->value); | |
} | |
args->result = 0; | |
v11->DecrementRefcount(v11); | |
} | |
else | |
{ | |
v10 = 0xD8E007F7; | |
LABEL_16: | |
args->result = v10; | |
} | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
v5 = CopyWordFromUser(&v15, &args->names[v4]) ? 0 : 0xE0E01BF5; | |
args->result = v5; | |
if ( v5 < 0 ) | |
break; | |
v6 = v15 >= RESLIMIT_MAX ? 0xD8E007ED : 0; | |
args->result = v6; | |
if ( v6 < 0 ) | |
break; | |
v7 = &pairs[v4]; | |
v7->name = v15; | |
v8 = CopyBytesFromUser(&dst, &args->values[v4], 8u) ? 0 : 0xE0E01BF5; | |
args->result = v8; | |
if ( v8 < 0 ) | |
break; | |
v9 = v17; | |
if ( v17 < 0 ) | |
{ | |
v10 = 0xD8E007FD; | |
goto LABEL_16; | |
} | |
LODWORD(v7->value) = dst; | |
++v4; | |
HIDWORD(v7->value) = v9; | |
if ( v4 >= args->count ) | |
goto LABEL_19; | |
} | |
} | |
} | |
// FFF2F0D4: using guessed type KernelSharedConfig *g_kernelSharedConfigPagePtr; | |
//----- (FFF0B6B8) -------------------------------------------------------- | |
Result __fastcall Run(Handle processHandle, const StartupInfo *info) | |
{ | |
KProcess *v3; // r0 | |
KProcess *v5; // r4 | |
Result v6; // r5 | |
v3 = KHandleTable::ConvertToProcessAllowPseudoHandle(¤t.clc.current.process->handleTable, processHandle); | |
if ( !v3 ) | |
return 0xD9001BF7; | |
v5 = v3; | |
v6 = KProcess::Run(v3, info->mainThreadPriority, info->stackSize); | |
v5->DecrementRefcount(v5); | |
return v6; | |
} | |
//----- (FFF0B710) -------------------------------------------------------- | |
Result __fastcall KEvent::Clear(KEvent *this) | |
{ | |
unsigned int v2; // r2 | |
bool v3; // zf | |
unsigned int v4; // r3 | |
BOOL manualInterruptReenable; // r0 | |
bool v6; // zf | |
Result v7; // r5 | |
v2 = __ldrex((unsigned int *)&g_eventSignalMutex); | |
v3 = v2 == 0; | |
if ( v2 ) | |
v4 = __strex(v2, (unsigned int *)&g_eventSignalMutex); | |
else | |
v4 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_eventSignalMutex); | |
if ( !v2 ) | |
v3 = v4 == 0; | |
if ( !v3 ) | |
KLightMutex::LockImpl(&g_eventSignalMutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
manualInterruptReenable = this->manualInterruptReenable; | |
this->signaled = 0; | |
v6 = !manualInterruptReenable; | |
if ( manualInterruptReenable ) | |
v6 = this->irqId == -1; | |
if ( v6 ) | |
{ | |
v7 = 0; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_eventSignalMutex.lockingThread = 0; | |
if ( g_eventSignalMutex.numWaiters <= 0 ) | |
return v7; | |
goto LABEL_12; | |
} | |
v7 = KInterruptEvent::ReenableInterrupt(this);// this is referred to as "(manual) clear" in some places | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_eventSignalMutex.lockingThread = 0; | |
if ( g_eventSignalMutex.numWaiters > 0 ) | |
LABEL_12: | |
KLightMutex::UnlockImpl(&g_eventSignalMutex); | |
return v7; | |
} | |
//----- (FFF0B7C4) -------------------------------------------------------- | |
Result __fastcall KEvent::Signal(KEvent *this) | |
{ | |
unsigned int v2; // r2 | |
bool v3; // zf | |
unsigned int v4; // r3 | |
v2 = __ldrex((unsigned int *)&g_eventSignalMutex); | |
v3 = v2 == 0; | |
if ( v2 ) | |
v4 = __strex(v2, (unsigned int *)&g_eventSignalMutex); | |
else | |
v4 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_eventSignalMutex); | |
if ( !v2 ) | |
v3 = v4 == 0; | |
if ( !v3 ) | |
KLightMutex::LockImpl(&g_eventSignalMutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( !this->signaled ) | |
{ | |
this->signaled = 1; | |
KSynchronizationObject::NotifyWaiters(this, this->resetType == RESET_PULSE); | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_eventSignalMutex.lockingThread = 0; | |
if ( g_eventSignalMutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_eventSignalMutex); | |
return 0; | |
} | |
//----- (FFF0B854) -------------------------------------------------------- | |
Result __fastcall KMutex::Unlock(KMutex *this, KThread *thread) | |
{ | |
s32 lockCount; // r0 | |
s32 v6; // r0 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( this->lockingThread == thread ) | |
{ | |
lockCount = this->lockCount; | |
if ( lockCount > 0 ) | |
{ | |
v6 = lockCount - 1; | |
this->lockCount = v6; | |
if ( !v6 ) | |
{ | |
this->lockingThread = 0; | |
KThread::RelinquishMutex(thread, this); | |
KSynchronizationObject::NotifyWaiters(this, 0); | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
else | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0xD8A007FF; | |
} | |
} | |
else | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0xD8E0041F; | |
} | |
} | |
//----- (FFF0B8F4) -------------------------------------------------------- | |
Result __fastcall KTimer::Clear(KTimer *this) | |
{ | |
this->signaled = 0; | |
return 0; | |
} | |
//----- (FFF0B904) -------------------------------------------------------- | |
Result __fastcall KTimer::Cancel(KTimer *this) | |
{ | |
Result result; // r0 | |
this->allowedToRegister = 0; | |
if ( KHardwareTimer::CancelTask(&g_hardwareTimer, &this->KTimerTask) ) | |
this->DecrementRefcount(this); | |
result = 0; | |
this->signaled = 0; | |
return result; | |
} | |
//----- (FFF0B948) -------------------------------------------------------- | |
bool __fastcall KInterruptManager::HandleIncomingInterrupt(KInterruptManager *this) | |
{ | |
KIrqAcknowledgmentInfo v2; // kr00_8 | |
KInterruptEntry *handler; // r5 | |
KInterruptEntry *v4; // r5 | |
KInterruptHandler *v5; // t1 | |
KInterruptTask *v6; // r5 | |
KIrqAcknowledgmentInfo v8; // [sp+0h] [bp-20h] BYREF | |
KInterruptController::AcknowledgeIrq(&v8); | |
v2 = v8; | |
if ( v8.irqId == 1023 ) // spurious | |
return 0; | |
if ( v8.irqId <= 0x1F ) | |
{ | |
handler = &this->privateInterrupts[__mrc(15, 0, 0, 0, 5) & 3][v2.irqId]; | |
if ( handler->handler ) | |
{ | |
if ( !handler->autoDisable_ManualClear ) | |
goto LABEL_11; | |
KInterruptController::SetInterruptPriority(v2.irqId, 0xFu); | |
goto LABEL_10; | |
} | |
LABEL_15: | |
KInterruptController::EndOfInterrupt(v2.irqId, v2.coreId); | |
return 0; | |
} | |
if ( v8.irqId - 0x20 > 0x5F ) | |
goto LABEL_15; | |
v4 = (KInterruptEntry *)((char *)this + 8 * v8.irqId - 0x100); | |
v5 = v4[128].handler; | |
handler = v4 + 128; | |
if ( !v5 ) | |
goto LABEL_15; | |
if ( !handler->autoDisable_ManualClear ) | |
goto LABEL_11; | |
KInterruptController::DisableInterrupt(v8.irqId); | |
LABEL_10: | |
handler->disabled = 1; | |
LABEL_11: | |
__mcr(15, 0, 0, 7, 10, 4); | |
v6 = handler->handler->OnInterrupt(handler->handler, v2.irqId); | |
KInterruptController::EndOfInterrupt(v2.irqId, v2.coreId); | |
if ( !v6 ) | |
return 0; | |
if ( v6 != (KInterruptTask *)1 ) | |
KInterruptTaskManager::EnqueueTask(current.clc.current.interruptTaskManager, v6); | |
return 1; | |
} | |
//----- (FFF0BA5C) -------------------------------------------------------- | |
Result __fastcall SetHardwareBreakpoint(s32 regId, u32 cr, u32 vr) | |
{ | |
KDebug *v6; // r0 | |
KDebug *v7; // r7 | |
KDebug *debug; // r4 | |
u8 typeId; // r10 | |
KTypeObj v11; // [sp+0h] [bp-30h] BYREF | |
KTypeObj v12; // [sp+8h] [bp-28h] BYREF | |
__mcr(14, 0, __mrc(14, 0, 0, 1, 0) | 0x8000, 0, 1, 0);// enable monitor-mode debugging | |
if ( (cr & 0x200000) != 0 ) // if vr type = contextId, get it from the debug handle | |
{ | |
v6 = (KDebug *)KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, vr); | |
v7 = v6; | |
if ( !v6 ) | |
return 0xD9002002; | |
debug = v6; | |
v6->GetTypeObj(&v11, v6); | |
typeId = v11.typeId; | |
debug->GetTypeObj(&v12, debug); | |
if ( (typeId | 0x4D) != v12.typeId ) | |
{ | |
debug = 0; | |
v7->DecrementRefcount(v7); | |
} | |
if ( !debug ) | |
return 0xD9002002; | |
vr = debug->process->pgTable.asid; // context id = asid in HOS | |
} | |
if ( regId == 4 ) | |
{ | |
__mcr(14, 0, __mrc(14, 0, 0, 4, 5) & ~1u, 0, 4, 5); | |
__mcr(14, 0, vr, 0, 4, 4); | |
__mcr(14, 0, cr, 0, 4, 5); | |
} | |
else if ( regId > 4 ) | |
{ | |
switch ( regId ) | |
{ | |
case 5: | |
__mcr(14, 0, __mrc(14, 0, 0, 5, 5) & ~1u, 0, 5, 5); | |
__mcr(14, 0, vr, 0, 5, 4); | |
__mcr(14, 0, cr, 0, 5, 5); | |
break; | |
case 256: | |
__mcr(14, 0, __mrc(14, 0, 0, 0, 7) & ~1u, 0, 0, 7); | |
__mcr(14, 0, vr, 0, 0, 6); | |
__mcr(14, 0, cr, 0, 0, 7); | |
break; | |
case 257: | |
__mcr(14, 0, __mrc(14, 0, 0, 1, 7) & ~1u, 0, 1, 7); | |
__mcr(14, 0, vr, 0, 1, 6); | |
__mcr(14, 0, cr, 0, 1, 7); | |
break; | |
} | |
} | |
else if ( regId ) | |
{ | |
switch ( regId ) | |
{ | |
case 1: | |
__mcr(14, 0, __mrc(14, 0, 0, 1, 5) & ~1u, 0, 1, 5); | |
__mcr(14, 0, vr, 0, 1, 4); | |
__mcr(14, 0, cr, 0, 1, 5); | |
break; | |
case 2: | |
__mcr(14, 0, __mrc(14, 0, 0, 2, 5) & ~1u, 0, 2, 5); | |
__mcr(14, 0, vr, 0, 2, 4); | |
__mcr(14, 0, cr, 0, 2, 5); | |
break; | |
case 3: | |
__mcr(14, 0, __mrc(14, 0, 0, 3, 5) & ~1u, 0, 3, 5); | |
__mcr(14, 0, vr, 0, 3, 4); | |
__mcr(14, 0, cr, 0, 3, 5); | |
break; | |
} | |
} | |
else | |
{ | |
__mcr(14, 0, __mrc(14, 0, 0, 0, 5) & ~1u, 0, 0, 5); | |
__mcr(14, 0, vr, 0, 0, 4); | |
__mcr(14, 0, cr, 0, 0, 5); | |
} | |
return 0; | |
} | |
//----- (FFF0BC44) -------------------------------------------------------- | |
Result __fastcall KDebug::ReadProcessMemory(KDebug *this, u32 dstAddr, u32 addr, u32 size) | |
{ | |
KProcess *process; // r0 | |
KThread *v7; // r2 | |
unsigned __int8 *p_dpcFlags; // r0 | |
unsigned __int8 v9; // r3 | |
u32 curAddr; // r4 | |
u32 endAddr; // r7 | |
Result result; // r0 | |
u32 v13; // r8 | |
u32 curOutAddr; // r4 | |
u32 endAddrDst; // r7 | |
u32 v16; // r2 | |
Result v17; // r4 | |
KProcessPageTable *srcPgTbl; // [sp+14h] [bp-5Ch] | |
KProcessPageTable *p_pgTable; // [sp+1Ch] [bp-54h] | |
KMemoryInfo outMemoryInfo; // [sp+20h] [bp-50h] BYREF | |
int pageInfo[3]; // [sp+34h] [bp-3Ch] BYREF | |
u32 v22; // [sp+40h] [bp-30h] | |
u32 v24; // [sp+48h] [bp-28h] | |
pageInfo[2] = (int)this; | |
v22 = dstAddr; | |
v24 = size; | |
process = this->process; | |
p_pgTable = ¤t.clc.current.process->pgTable; | |
srcPgTbl = &process->pgTable; | |
v7 = (KThread *)__ldrex((unsigned int *)&process->pgTable); | |
if ( v7 && v7->owner == process ) | |
{ | |
v7->debugThread->debugPauseRequested = 1; | |
p_dpcFlags = &ADJ(v7->kernelStackTop)->dpcFlags;// this code block here is kinda awful | |
// if the debug-paused thread (note: not checked!) was holding the memory manager mutex, unpause it and set dpc | |
// | |
// but this shouldn't happen because we always set dpc if the thread is in svc | |
do | |
v9 = __ldrex(p_dpcFlags); | |
while ( __strex(v9 | 4, p_dpcFlags) ); | |
KThread::SetDebugPauseState(v7, 0); | |
} | |
curAddr = addr; | |
endAddr = addr + size; | |
result = 0; | |
if ( addr < addr + size ) | |
{ | |
do | |
{ | |
result = KPageTable::QueryInfo(srcPgTbl, &outMemoryInfo, (u32 *)pageInfo, curAddr); | |
if ( result < 0 ) | |
break; | |
v13 = outMemoryInfo.baseAddress + outMemoryInfo.size >= endAddr ? endAddr - curAddr : outMemoryInfo.baseAddress | |
+ outMemoryInfo.size | |
- curAddr; | |
result = KPageTable::CheckAddrRangeMaskedStateAndPerms( | |
srcPgTbl, | |
curAddr, | |
v13, | |
KMEMSTATE_FLAG_DEBUGGABLE, // bug! Stuff like 0xBB05 (regular private data) doesn't have this flag... oops! | |
KMEMSTATE_FLAG_DEBUGGABLE, | |
KMEMPERM_NONE); | |
if ( result < 0 ) | |
{ | |
result = KPageTable::CheckAddrRangeMaskedStateAndPerms( | |
srcPgTbl, | |
curAddr, | |
v13, | |
MEMSTATE_FREE, | |
MEMSTATE_FREE, | |
KMEMPERM_R); | |
if ( result < 0 ) | |
break; | |
} | |
curAddr = outMemoryInfo.baseAddress + outMemoryInfo.size; | |
} | |
while ( outMemoryInfo.baseAddress + outMemoryInfo.size < endAddr ); | |
} | |
if ( result >= 0 ) | |
{ | |
curOutAddr = v22; | |
endAddrDst = v22 + size; | |
if ( v22 >= v22 + size ) | |
{ | |
LABEL_22: | |
result = 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
result = KPageTable::QueryInfo(p_pgTable, &outMemoryInfo, (u32 *)pageInfo, curOutAddr); | |
if ( result < 0 ) | |
break; | |
v16 = outMemoryInfo.baseAddress + outMemoryInfo.size >= endAddrDst ? endAddrDst - curOutAddr : outMemoryInfo.baseAddress + outMemoryInfo.size - curOutAddr; | |
result = KPageTable::CheckAddrRangeMaskedStateAndPerms( | |
p_pgTable, | |
curOutAddr, | |
v16, | |
MEMSTATE_FREE, | |
MEMSTATE_FREE, | |
KMEMPERM_W); | |
if ( result < 0 ) | |
break; | |
curOutAddr = outMemoryInfo.baseAddress + outMemoryInfo.size; | |
if ( outMemoryInfo.baseAddress + outMemoryInfo.size >= endAddrDst ) | |
goto LABEL_22; | |
} | |
} | |
if ( result >= 0 ) | |
{ | |
v17 = KProcessPageTable::CopyMemoryForDebug(p_pgTable, v22, srcPgTbl, addr, size); | |
KProcess::CleanInvalidateDataCacheRange(this->process, addr, size);// BUG: assumes paddr is in FCRAM | |
return v17; | |
} | |
} | |
return result; | |
} | |
// FFF0BC44: using guessed type u32 pageInfo[3]; | |
//----- (FFF0BE58) -------------------------------------------------------- | |
Result __fastcall KDebug::WriteProcessMemory(KDebug *this, u32 addr, u32 dstAddr, u32 size) | |
{ | |
KProcess *process; // r0 | |
KThread *v7; // r2 | |
unsigned __int8 *p_dpcFlags; // r0 | |
unsigned __int8 v9; // r3 | |
u32 v10; // r4 | |
u32 v11; // r7 | |
Result result; // r0 | |
u32 v13; // r8 | |
u32 v14; // r7 | |
u32 v15; // r4 | |
u32 v16; // r2 | |
Result v17; // r4 | |
KProcessPageTable *srcPageTable; // [sp+14h] [bp-5Ch] | |
KProcessPageTable *p_pgTable; // [sp+1Ch] [bp-54h] | |
KMemoryInfo outMemoryInfo; // [sp+20h] [bp-50h] BYREF | |
int pageInfo[3]; // [sp+34h] [bp-3Ch] BYREF | |
u32 srcAddr; // [sp+40h] [bp-30h] | |
u32 v24; // [sp+48h] [bp-28h] | |
pageInfo[2] = (int)this; | |
srcAddr = addr; | |
v24 = size; | |
process = this->process; | |
srcPageTable = ¤t.clc.current.process->pgTable; | |
p_pgTable = &process->pgTable; | |
v7 = (KThread *)__ldrex((unsigned int *)&process->pgTable); | |
if ( v7 && v7->owner == process ) | |
{ | |
v7->debugThread->debugPauseRequested = 1; // this code block here is awful | |
// if the debug-paused thread (note: not checked!) was holding the memory manager mutex, unpause it and set dpc | |
// | |
// but this shouldn't happen because we always set dpc if the thread is in svc | |
p_dpcFlags = &ADJ(v7->kernelStackTop)->dpcFlags; | |
do | |
v9 = __ldrex(p_dpcFlags); | |
while ( __strex(v9 | KDPCFLAG_DEBUG_PAUSE, p_dpcFlags) ); | |
KThread::SetDebugPauseState(v7, 0); | |
} | |
v10 = dstAddr; | |
v11 = dstAddr + size; | |
result = 0; | |
if ( dstAddr < dstAddr + size ) | |
{ | |
do | |
{ | |
result = KPageTable::QueryInfo(p_pgTable, &outMemoryInfo, (u32 *)pageInfo, v10); | |
if ( result < 0 ) | |
break; | |
v13 = outMemoryInfo.baseAddress + outMemoryInfo.size >= v11 ? v11 - v10 : outMemoryInfo.baseAddress | |
+ outMemoryInfo.size | |
- v10; | |
result = KPageTable::CheckAddrRangeMaskedStateAndPerms( | |
p_pgTable, | |
v10, | |
v13, | |
KMEMSTATE_FLAG_DEBUGGABLE, // bug! Stuff like 0xBB05 (regular private data) doesn't have this flag... oops! | |
KMEMSTATE_FLAG_DEBUGGABLE, | |
KMEMPERM_NONE); | |
if ( result < 0 ) | |
{ | |
result = KPageTable::CheckAddrRangeMaskedStateAndPerms( | |
p_pgTable, | |
v10, | |
v13, | |
MEMSTATE_FREE, | |
MEMSTATE_FREE, | |
KMEMPERM_W); | |
if ( result < 0 ) | |
break; | |
} | |
v10 = outMemoryInfo.baseAddress + outMemoryInfo.size; | |
} | |
while ( outMemoryInfo.baseAddress + outMemoryInfo.size < v11 ); | |
} | |
if ( result >= 0 ) | |
{ | |
v14 = srcAddr; | |
v15 = srcAddr + size; | |
if ( srcAddr >= srcAddr + size ) | |
{ | |
LABEL_22: | |
result = 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
result = KPageTable::QueryInfo(srcPageTable, &outMemoryInfo, (u32 *)pageInfo, v14); | |
if ( result < 0 ) | |
break; | |
v16 = outMemoryInfo.baseAddress + outMemoryInfo.size >= v15 ? v15 - v14 : outMemoryInfo.baseAddress | |
+ outMemoryInfo.size | |
- v14; | |
result = KPageTable::CheckAddrRangeMaskedStateAndPerms( | |
srcPageTable, | |
v14, | |
v16, | |
MEMSTATE_FREE, | |
MEMSTATE_FREE, | |
KMEMPERM_R); | |
if ( result < 0 ) | |
break; | |
v14 = outMemoryInfo.baseAddress + outMemoryInfo.size; | |
if ( outMemoryInfo.baseAddress + outMemoryInfo.size >= v15 ) | |
goto LABEL_22; | |
} | |
} | |
if ( result >= 0 ) | |
{ | |
v17 = KProcessPageTable::CopyMemoryForDebug(p_pgTable, dstAddr, srcPageTable, srcAddr, size); | |
KProcess::CleanInvalidateDataCacheRange(this->process, dstAddr, size); | |
KPageTable::InvalidateEntireInstructionCache(); | |
return v17; | |
} | |
} | |
return result; | |
} | |
// FFF0BE58: using guessed type u32 pageInfo[3]; | |
//----- (FFF0C078) -------------------------------------------------------- | |
Result __fastcall KDebug::BreakProcess(KDebug *this) | |
{ | |
KSchedulerLock *p_lock; // r5 | |
BOOL signalingSyncEvent; // r0 | |
bool v4; // zf | |
int v5; // r0 | |
char cfgr; // r1 | |
int v7; // r3 | |
KThread *thread; // r2 | |
KThreadLinkedListNode *node; // r1 | |
u32 threadId; // r1 | |
KProcess *process; // r0 | |
KThread *v12; // r1 | |
KThread *v13; // r1 | |
KThread *v14; // r2 | |
ExceptionDispatchContext *excCtx; // r0 | |
u32 pc; // r3 | |
Result result; // r0 | |
s32 threadIds[4]; // [sp+18h] [bp-30h] BYREF | |
p_lock = &this->lock; | |
memset(threadIds, 0, sizeof(threadIds)); | |
KSchedulerLock::Lock(&this->lock); | |
KSchedulerLock::Lock(&g_schedulerLock); | |
signalingSyncEvent = this->signalingSyncEvent; | |
this->hasDebuggerBreak = 1; | |
v4 = !signalingSyncEvent; | |
if ( !signalingSyncEvent ) | |
v4 = !this->hasBreakSvc; | |
if ( v4 ) | |
KDebug::PauseProcess(this, 0); | |
v5 = 0; | |
cfgr = MPCORE.scu.cfgr; | |
v7 = (cfgr & 3) + 1; | |
while ( v7 > v5 ) | |
{ | |
for ( node = this->orderedThreadListForBreak.link.next; ; node = node->link.next ) | |
{ | |
if ( node == (KThreadLinkedListNode *)&this->orderedThreadListForBreak.link ) | |
{ | |
threadId = -1; | |
goto LABEL_12; | |
} | |
thread = node->thread; | |
if ( thread->coreId == v5 && !ADJ(thread->kernelStackTop)->svcId ) | |
break; | |
} | |
threadId = thread->threadId; | |
LABEL_12: | |
threadIds[v5++] = threadId; | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
KSchedulerLock::UnlockSingleCoreResched(p_lock); | |
process = this->process; | |
v12 = (KThread *)__ldrex((unsigned int *)&g_eventSignalMutex);// avoid deadlock? | |
// pause the thread we might not have paused before | |
if ( v12 ) | |
{ | |
if ( v12->owner == process ) | |
{ | |
v13 = (KThread *)__ldrex((unsigned int *)&g_eventSignalMutex); | |
if ( v13 ) | |
{ | |
if ( v13->owner == process && (v13->coreId & 0x80000000) == 0 && !v13->debugThread->debugPauseRequested ) | |
{ | |
v14 = (KThread *)__ldrex((unsigned int *)&g_eventSignalMutex); | |
if ( v14 ) | |
{ | |
if ( v14->owner == process && (v14->coreId & 0x80000000) == 0 ) | |
{ | |
v14->debugThread->debugPauseRequested = 1; | |
KThread::SetDebugPauseState(v14, 0); | |
} | |
} | |
} | |
} | |
} | |
} | |
excCtx = this->excCtx; | |
if ( excCtx ) | |
pc = excCtx->pc; | |
else | |
pc = ADJ(this->process->mainThread->kernelStackTop)[-1].ctx.fpexc; | |
result = KDebug::EmplaceAysncEventInfo( | |
this, | |
DBGEVENT_EXCEPTION, | |
1, | |
pc, | |
EXCEVENT_DEBUGGER_BREAK, | |
threadIds[0], | |
threadIds[1], | |
threadIds[2], | |
threadIds[3]); | |
if ( result >= 0 ) | |
{ | |
KSynchronizationObject::NotifyWaiters(this, 0); | |
return 0; | |
} | |
return result; | |
} | |
//----- (FFF0C27C) -------------------------------------------------------- | |
Result __fastcall KDebug::Continue(KDebug *this, DebugFlags debugFlags) | |
{ | |
int v4; // r9 | |
unsigned int CPSR; // r7 | |
KThread *userDebuggerThread; // r0 | |
KThread *volatile thread; // r8 | |
KLinkedListNode *v8; // r0 | |
KEventInfoLinkedListNode *next; // r8 | |
KEventInfo *eventInfo; // r4 | |
KEventInfo *v11; // r1 | |
DebugEventType type; // r0 | |
bool v13; // zf | |
bool v14; // zf | |
u16 v15; // r0 | |
BOOL v16; // r1 | |
KThread *v17; // r0 | |
bool v18; // zf | |
KThread *userBreakThread; // r0 | |
u16 numBlockingEvents; // r0 | |
BOOL hasAttachBreak; // r1 | |
KEventInfoLinkedListNode *v23; // [sp+0h] [bp-28h] BYREF | |
v4 = 1; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
userDebuggerThread = this->userDebuggerThread; | |
this->debugFlags = debugFlags; | |
if ( !userDebuggerThread ) | |
{ | |
thread = current.clc.current.thread; | |
this->userDebuggerThread = current.clc.current.thread; | |
this->userDebuggerCoreId = __mrc(15, 0, 0, 0, 5) & 3; | |
v8 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v8 ) | |
{ | |
v8->link.next = 0; | |
v8->link.prev = 0; | |
v8->data = 0; | |
} | |
v8->data = thread; | |
KLinkedList::InsertAfter( | |
(KLinkedList *)&g_debuggerThreadLinkedList, | |
(KLinkedListLink *)&g_debuggerThreadLinkedList.link, | |
v8); | |
} | |
KSchedulerLock::Lock(&g_schedulerLock); | |
next = this->eventsToContinue.link.next; | |
eventInfo = next->eventInfo; | |
v23 = next; | |
KLinkedList::EraseNode((KLinkedList *)&this->eventsToContinue, (KLinkedListLink **)&v23); | |
KSlabHeap::Free(&g_linkedListNodeSlabHeap, next); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
if ( this->numAttachOrDetachEvents ) | |
{ | |
--this->numAttachOrDetachEvents; | |
v11 = eventInfo; | |
--this->numBlockingEvents; | |
if ( eventInfo->needsToBeContinued && !eventInfo->isProcessed ) | |
{ | |
LABEL_8: | |
eventInfo->isProcessed = 1; | |
goto LABEL_71; | |
} | |
LABEL_9: | |
KSlabHeap::Free(&g_eventInfoSlabHeap, v11); | |
goto LABEL_71; | |
} | |
type = eventInfo->type; | |
if ( !this->hasDebuggerBreak ) | |
{ | |
v18 = type == DBGEVENT_EXCEPTION; | |
if ( type == DBGEVENT_EXCEPTION ) | |
v18 = eventInfo->d.exception.type == EXCEVENT_USER_BREAK; | |
if ( v18 ) | |
{ | |
userBreakThread = this->userBreakThread; | |
--this->numBlockingEvents; | |
if ( userBreakThread ) | |
KThread::SetDebugPauseState(userBreakThread, 0); | |
else | |
KDebug::UnpauseAllThreads(this, 0); | |
this->hasBreakSvc = 0; | |
if ( !eventInfo->needsToBeContinued || eventInfo->isProcessed ) | |
KSlabHeap::Free(&g_eventInfoSlabHeap, eventInfo); | |
else | |
eventInfo->isProcessed = 1; | |
} | |
else // other exceptions | |
{ | |
if ( eventInfo->ignoreContinue ) | |
{ | |
v11 = eventInfo; | |
--this->numBlockingEvents; | |
if ( eventInfo->needsToBeContinued && !eventInfo->isProcessed ) | |
goto LABEL_8; | |
goto LABEL_9; | |
} | |
if ( !eventInfo->needsToBeContinued || eventInfo->isProcessed ) | |
KSlabHeap::Free(&g_eventInfoSlabHeap, eventInfo); | |
else | |
eventInfo->isProcessed = 1; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
numBlockingEvents = this->numBlockingEvents; | |
hasAttachBreak = this->hasAttachBreak; | |
this->excCtx = 0; | |
this->numBlockingEvents = numBlockingEvents - 1; | |
if ( hasAttachBreak ) | |
{ | |
KDebug::UnpauseAllThreads(this, 1); | |
this->hasAttachBreak = 0; | |
} | |
else | |
{ | |
this->signalingSyncEventThread->debugThread->debugPauseRequested = 0; | |
KThread::SetDebugPauseState(this->signalingSyncEventThread, 0); | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
LABEL_70: | |
this->signalingSyncEvent = 0; | |
goto LABEL_71; | |
} // endif (!hasDebuggerBreak) | |
v13 = type == DBGEVENT_EXCEPTION; | |
if ( type == DBGEVENT_EXCEPTION ) | |
v13 = eventInfo->d.exception.type == EXCEVENT_DEBUGGER_BREAK; | |
if ( !v13 ) | |
{ | |
v14 = type == DBGEVENT_EXCEPTION; | |
if ( type == DBGEVENT_EXCEPTION ) | |
type = eventInfo->d.exception.type; | |
v11 = eventInfo; | |
if ( v14 ) | |
v14 = type == DBGEVENT_DLL_UNLOAD; | |
if ( v14 ) | |
this->deferredUserBreakContinue = 1; | |
else | |
this->deferredExceptionContinue = 1; | |
--this->numBlockingEvents; | |
if ( eventInfo->needsToBeContinued && !eventInfo->isProcessed ) | |
goto LABEL_8; | |
goto LABEL_9; | |
} | |
if ( this->deferredExceptionContinue ) | |
{ | |
this->deferredExceptionContinue = 0; | |
if ( !eventInfo->needsToBeContinued || eventInfo->isProcessed ) | |
KSlabHeap::Free(&g_eventInfoSlabHeap, eventInfo); | |
else | |
eventInfo->isProcessed = 1; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
v15 = this->numBlockingEvents; | |
v16 = this->hasAttachBreak; | |
this->excCtx = 0; | |
this->numBlockingEvents = v15 - 1; | |
if ( v16 ) | |
{ | |
KDebug::UnpauseAllThreads(this, 1); | |
this->hasAttachBreak = 0; | |
} | |
else | |
{ | |
this->signalingSyncEventThread->debugThread->debugPauseRequested = 0; | |
KThread::SetDebugPauseState(this->signalingSyncEventThread, 0); | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
else if ( this->deferredUserBreakContinue ) | |
{ | |
this->deferredUserBreakContinue = 0; | |
if ( !eventInfo->needsToBeContinued || eventInfo->isProcessed ) | |
KSlabHeap::Free(&g_eventInfoSlabHeap, eventInfo); | |
else | |
eventInfo->isProcessed = 1; | |
v17 = this->userBreakThread; | |
--this->numBlockingEvents; | |
if ( v17 ) | |
KThread::SetDebugPauseState(v17, 0); | |
else | |
KDebug::UnpauseAllThreads(this, 0); | |
this->hasBreakSvc = 0; | |
} | |
else | |
{ | |
if ( !eventInfo->needsToBeContinued || eventInfo->isProcessed ) | |
KSlabHeap::Free(&g_eventInfoSlabHeap, eventInfo); | |
else | |
eventInfo->isProcessed = 1; | |
--this->numBlockingEvents; | |
KDebug::UnpauseAllThreads(this, 0); | |
v4 = 0; | |
} | |
this->hasDebuggerBreak = 0; | |
if ( v4 ) | |
goto LABEL_70; | |
LABEL_71: | |
__set_CPSR(CPSR); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
// FFF0C2F0: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF0C6DC) -------------------------------------------------------- | |
Result __fastcall KDebug::EraseFirstEventInfoToFetchNode(KDebug *this) | |
{ | |
KEventInfoLinkedList *p_eventsToFetch; // r0 | |
KLinkedListLink *next; // r4 | |
KLinkedListLink *v5; // [sp+0h] [bp-10h] BYREF | |
KSchedulerLock::Lock(&g_schedulerLock); | |
p_eventsToFetch = &this->eventsToFetch; | |
next = (KLinkedListLink *)this->eventsToFetch.link.next; | |
v5 = next; | |
KLinkedList::EraseNode((KLinkedList *)p_eventsToFetch, &v5); | |
KSlabHeap::Free(&g_linkedListNodeSlabHeap, next); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
//----- (FFF0C728) -------------------------------------------------------- | |
Result __fastcall KDebug::GetPausedThreadContextById( | |
KDebug *this, | |
ThreadContext *outThreadContext, | |
u32 tid, | |
ThreadContextControlFlags flags) | |
{ | |
KDebugThreadLinkedListNode *i; // r2 | |
KThread *thread; // r4 | |
KDebugThread *debugThread; // r2 | |
bool v12; // zf | |
Result ThreadContext; // r4 | |
for ( i = this->debugThreads.link.next; ; i = i->link.next ) | |
{ | |
if ( i == (KDebugThreadLinkedListNode *)&this->debugThreads.link ) | |
return 0xD88007EF; | |
thread = i->debugThread->thread; | |
if ( (thread->schedulingMask & 0xF) != KTHREADSCHEDSTAT_TERMINATED && thread->threadId == tid ) | |
break; | |
} | |
if ( !thread || thread->owner != this->process ) | |
return 0xD88007EF; | |
debugThread = thread->debugThread; | |
if ( (unsigned __int8)(debugThread->thread->schedulingMask & 0x80) >> 7 )// | |
// we can access the thread ctx if at least one of the following is true: | |
// | |
// - the thread debug paused | |
// - the thread is in a svc and is about to be debug paused | |
// - the thread is paused | |
goto LABEL_17; | |
v12 = ADJ(debugThread->thread->kernelStackTop)->svcId == 0; | |
if ( !ADJ(debugThread->thread->kernelStackTop)->svcId ) | |
v12 = !debugThread->debugPauseRequested; | |
if ( v12 && (debugThread->thread->schedulingMask & 0xF) != 0 ) | |
return 0xD90007EE; | |
LABEL_17: | |
KSchedulerLock::Lock(&g_schedulerLock); | |
ThreadContext = KDebug::GetThreadContext(this, outThreadContext, thread, flags); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return ThreadContext; | |
} | |
//----- (FFF0C824) -------------------------------------------------------- | |
BOOL __fastcall KDebug::NeedsContinue(KDebug *this) | |
{ | |
return this->numBlockingEvents != 0; | |
} | |
//----- (FFF0C834) -------------------------------------------------------- | |
Result __fastcall KDebug::SetPausedThreadContextById( | |
KDebug *this, | |
ThreadContext *threadContext, | |
u32 tid, | |
ThreadContextControlFlags flags) | |
{ | |
KDebugThreadLinkedListNode *i; // r2 | |
KThread *thread; // r4 | |
KDebugThread *debugThread; // r2 | |
bool v12; // zf | |
Result v13; // r4 | |
for ( i = this->debugThreads.link.next; ; i = i->link.next ) | |
{ | |
if ( i == (KDebugThreadLinkedListNode *)&this->debugThreads.link ) | |
return 0xD88007EF; | |
thread = i->debugThread->thread; | |
if ( (thread->schedulingMask & 0xF) != KTHREADSCHEDSTAT_TERMINATED && thread->threadId == tid ) | |
break; | |
} | |
if ( !thread || thread->owner != this->process ) | |
return 0xD88007EF; | |
debugThread = thread->debugThread; | |
if ( (unsigned __int8)(debugThread->thread->schedulingMask & KTHREADSCHEDSTAT_DEBUG_PAUSE_FLAG) >> 7 )// | |
// we can access the thread ctx if at least one of the following is true: | |
// | |
// - the thread debug paused | |
// - the thread is in a svc and is about to be debug paused | |
// - the thread is paused | |
goto LABEL_17; | |
v12 = ADJ(debugThread->thread->kernelStackTop)->svcId == 0; | |
if ( !ADJ(debugThread->thread->kernelStackTop)->svcId ) | |
v12 = !debugThread->debugPauseRequested; | |
if ( v12 && (debugThread->thread->schedulingMask & 0xF) != 0 ) | |
return 0xD90007EE; | |
LABEL_17: | |
KSchedulerLock::Lock(&g_schedulerLock); | |
v13 = KDebug::SetThreadContext(this, threadContext, thread, flags); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return v13; | |
} | |
//----- (FFF0C930) -------------------------------------------------------- | |
Result __fastcall KDebug::TerminateProcess(KDebug *this) | |
{ | |
KProcess *process; // r0 | |
if ( this->processTerminated ) | |
return 0xD8800608; | |
process = this->process; | |
if ( !process || KProcess::IsTerminated(process) ) | |
return 0xD8800608; | |
KWorkerTaskManager::AddTask(KWORKERTYPE_HIGH_PRIO, &this->KWorkerTask); | |
return 0; | |
} | |
//----- (FFF0C97C) -------------------------------------------------------- | |
Result __fastcall BreakImpl(UserBreakType breakReason, u32 croInfoAddr, u32 croInfoSize) | |
{ | |
KDebug *debug; // r5 | |
bool v5; // zf | |
KThread *currentThread; // r9 | |
bool v10; // zf | |
int v11; // r4 | |
debug = current.clc.current.process->debug; | |
if ( !debug ) | |
return 0; | |
v5 = breakReason == USERBREAK_LOAD_RO; | |
if ( breakReason != USERBREAK_LOAD_RO ) | |
v5 = breakReason == USERBREAK_UNLOAD_RO; | |
if ( !v5 ) | |
return KDebug::BreakNoRo(current.clc.current.process->debug, breakReason); | |
currentThread = current.clc.current.thread; // else | |
KDebug::BreakCurrentProcess(current.clc.current.process->debug, current.clc.current.thread); | |
KSchedulerLock::Lock(&g_schedulerLock); | |
debug->userBreakThread = currentThread; | |
KThread::SetDebugPauseState(currentThread, 1); | |
v10 = breakReason == USERBREAK_LOAD_RO; | |
if ( breakReason != USERBREAK_LOAD_RO ) | |
v10 = breakReason == USERBREAK_UNLOAD_RO; | |
if ( !v10 ) | |
kernelpanic(); | |
v11 = KDebug::EmplaceAysncEventInfo( | |
debug, | |
DBGEVENT_EXCEPTION, | |
1, | |
breakReason, | |
EXCEVENT_USER_BREAK, | |
croInfoAddr, | |
croInfoSize, | |
0, | |
0); | |
if ( v11 >= 0 ) | |
{ | |
KSynchronizationObject::NotifyWaiters(debug, 0); | |
KDebug::RequestReschedulingForDebugger(debug, debug->userDebuggerCoreId); | |
KDebug::RequestReschedulingForDebugger(debug, __mrc(15, 0, 0, 0, 5) & 3); | |
KSchedulerLock::Unlock(&g_schedulerLock); // pause here | |
KSchedulerLock::Lock(&g_schedulerLock); | |
debug->userBreakThread = 0; | |
KDebug::UnbreakCurrentProcess(debug); | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return v11; | |
} | |
//----- (FFF0CAD4) -------------------------------------------------------- | |
void __fastcall KDebug::ProcessEventInfo(KDebug *this, DebugEventType type, KEventInfo *info) | |
{ | |
if ( !info->needsToBeContinued || info->isProcessed ) | |
KSlabHeap::Free(&g_eventInfoSlabHeap, info); | |
else | |
info->isProcessed = 1; | |
} | |
//----- (FFF0CB08) -------------------------------------------------------- | |
KEventInfo *__fastcall KDebug::GetFirstEventInfoToFetch(KDebug *this) | |
{ | |
KEventInfo *eventInfo; // r4 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( this->eventsToFetch.count ) | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
KSchedulerLock::Lock(&g_schedulerLock); | |
eventInfo = this->eventsToFetch.link.next->eventInfo; | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return eventInfo; | |
} | |
else | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
} | |
//----- (FFF0CB60) -------------------------------------------------------- | |
void __fastcall KThread::HandleDpc(KThread *this) | |
{ | |
u8 schedulingMask; // r2 | |
KMutex *v3; // r0 | |
KMutexIntrusiveLinkPtr p_link; // r2 | |
bool v5; // zf | |
KThreadStackParametersPtr v6; // r1 | |
u8 dpcFlags; // r12 | |
unsigned __int8 *p_dpcFlags; // r0 | |
if ( this->shallTerminate ) | |
{ | |
__enable_irq(); | |
KThread::SignalExitToDebug(this); // inlined KThread::Exit | |
KHardwareTimer::CancelTask(&g_hardwareTimer, &this->KTimerTask); | |
KSchedulerLock::Lock(&g_schedulerLock); | |
KSchedulerLock::Lock(&g_schedulerLock); | |
schedulingMask = this->schedulingMask; | |
this->schedulingMask = schedulingMask & 0xF0 | KTHREADSCHEDSTAT_TERMINATED; | |
KScheduler::AdjustThreadScheduling(current.clc.current.scheduler, this, schedulingMask); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
KScheduler::RemoveTerminatingThread(current.clc.current.scheduler, this); | |
this->signaled = 1; | |
KSynchronizationObject::NotifyWaiters(this, 0); | |
while ( 1 ) | |
{ | |
p_link = &ADJ(this->heldMutexListRootNode)->link; | |
v5 = p_link == 0; | |
if ( p_link ) | |
{ | |
v3 = ADJ(p_link); | |
v5 = p_link == (KMutexIntrusiveLinkPtr)20; | |
} | |
if ( v5 ) | |
{ | |
KThread::RemoveVfpUsageFromCurrentContext(this); | |
KWorkerTaskManager::AddTask(KWORKERTYPE_LOW_PRIO, &this->KWorkerTask); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
kernelpanic(); | |
} | |
KMutex::ForceUnlock(v3, this); | |
} | |
} | |
if ( (ADJ(this->kernelStackTop)->dpcFlags & KDPCFLAG_TERMINATE) != 0 ) | |
KThread::HandleDebugStopDpc(this); // Wrong DPC flag! | |
// | |
// This means the anti event/pg table deadlock stuff doesn't work (thread will resume execution!) | |
// | |
// This also means attached thread may hang termination forever | |
v6 = ADJ(this->kernelStackTop) + 1; | |
dpcFlags = ADJ(v6)->dpcFlags; | |
p_dpcFlags = &ADJ(v6)->dpcFlags; | |
do | |
__ldrex(p_dpcFlags); | |
while ( __strex(0, p_dpcFlags) ); | |
if ( (dpcFlags & KDPCFLAG_OUT_OF_TIME_PAUSE) != 0 ) | |
KScheduler::TrySwitchingThread(current.clc.current.scheduler); | |
} | |
// FFF0CBF8: variable 'v3' is possibly undefined | |
//----- (FFF0CCA8) -------------------------------------------------------- | |
KCodeSet *__fastcall KCodeSet::KCodeSet(KCodeSet *this) | |
{ | |
KCodeSet *v1; // r0 | |
KCodeSegment *__shifted(KCodeSet,8) v2; // r0 | |
KCodeSegment *__shifted(KCodeSet,0x1C) v3; // r0 | |
KCodeSet *result; // r0 | |
v1 = (KCodeSet *)KAutoObject::KAutoObject(this); | |
v1->__vftable = &KCodeSet::vt; | |
v2 = KCodeSegment::KCodeSegment(&v1->text); | |
v3 = KCodeSegment::KCodeSegment(&ADJ(v2)->rodata); | |
result = CONTAINING_RECORD(KCodeSegment::KCodeSegment(&ADJ(v3)->data), KCodeSet, data); | |
result->numCodePages = 0; | |
result->numConstPages = 0; | |
result->numDataPages = 0; | |
return result; | |
} | |
//----- (FFF0CCE8) -------------------------------------------------------- | |
Result __fastcall KProcess::Initialize(KProcess *this, KCodeSet *codeSet, u32 *kernelCaps, u32 numCaps) | |
{ | |
unsigned __int8 *p_state; // r0 | |
u32 v8; // r0 | |
unsigned int *p_kernAllocatedForProcess; // r0 | |
u32 pid; // r8 | |
bool ShouldOnlyUseSmallPages; // r0 | |
unsigned __int16 *p_threadCount; // r0 | |
unsigned int *p_unused_234; // r0 | |
unsigned __int64 *p_unused_238; // r3 | |
unsigned __int64 *p_unused_240; // r3 | |
unsigned __int64 *p_unused_248; // r3 | |
unsigned __int64 *p_unused_250; // r3 | |
unsigned __int64 *p_unused_258; // r3 | |
unsigned __int64 *p_unused_260; // r3 | |
unsigned __int64 *p_unused_268; // r3 | |
Result result; // r0 | |
u32 LinearAddrRangeBase; // r0 | |
u32 kernelFlags; // r1 | |
p_state = (unsigned __int8 *)&this->state; | |
do | |
__ldrex(p_state); | |
while ( __strex(0, p_state) ); | |
this->mainThread = 0; | |
this->codeSet = codeSet; | |
this->reslimit = 0; | |
do | |
v8 = __ldrex(&g_pidCounter); | |
while ( __strex(v8 + 1, &g_pidCounter) ); | |
this->pid = v8; | |
this->creationTime = KHardwareTimer::GetSystemTick(&g_hardwareTimer); | |
p_kernAllocatedForProcess = &this->kernAllocatedForProcess; | |
do | |
__ldrex(p_kernAllocatedForProcess); | |
while ( __strex(0, p_kernAllocatedForProcess) ); | |
pid = this->pid; | |
ShouldOnlyUseSmallPages = KProcess::ShouldOnlyUseSmallPages(this->codeSet->titleId); | |
KProcessPageTable::Initialize(&this->pgTable, pid, ShouldOnlyUseSmallPages); | |
KAutoObject::IncrementRefcount(this->codeSet); | |
KProcess::ChangeAffinityMask(&this->affinityMask, 0, 1); | |
this->idealProcessor = -1; | |
p_threadCount = (unsigned __int16 *)&this->threadCount; | |
do | |
__ldrex(p_threadCount); | |
while ( __strex(0, p_threadCount) ); | |
p_unused_234 = &this->unused_234; | |
this->maxAllowedThreadCount = 0; | |
do | |
__ldrex(p_unused_234); | |
while ( __strex(0, p_unused_234) ); | |
p_unused_238 = &this->unused_238; | |
do | |
__ldrexd(p_unused_238); | |
while ( __strexd(0LL, p_unused_238) ); | |
p_unused_240 = &this->unused_240; | |
do | |
__ldrexd(p_unused_240); | |
while ( __strexd(0LL, p_unused_240) ); | |
p_unused_248 = &this->unused_248; | |
do | |
__ldrexd(p_unused_248); | |
while ( __strexd(0LL, p_unused_248) ); | |
p_unused_250 = &this->unused_250; | |
do | |
__ldrexd(p_unused_250); | |
while ( __strexd(0LL, p_unused_250) ); | |
p_unused_258 = &this->unused_258; | |
do | |
__ldrexd(p_unused_258); | |
while ( __strexd(0LL, p_unused_258) ); | |
p_unused_260 = &this->unused_260; | |
do | |
__ldrexd(p_unused_260); | |
while ( __strexd(0LL, p_unused_260) ); | |
p_unused_268 = &this->unused_268; | |
do | |
__ldrexd(p_unused_268); | |
while ( __strexd(0LL, p_unused_268) ); | |
this->boundIrqIds[0] = 0; | |
this->boundIrqIds[1] = 0; | |
this->boundIrqIds[2] = 0; | |
this->boundIrqIds[3] = 0; | |
result = KCapability::Initialize(&this->capability, kernelCaps, numCaps, &this->pgTable); | |
if ( result >= 0 ) | |
{ | |
LinearAddrRangeBase = KProcess::GetLinearAddrRangeBase(this); | |
kernelFlags = this->capability.kernelFlags; | |
this->pgTable.linearAddressRangeStart = LinearAddrRangeBase; | |
KProcessPageTable::MapSharedConfigPages(&this->pgTable, (kernelFlags & 8) != 0);// Shared page writing cap | |
KHandleTable::Initialize(&this->handleTable, this->capability.handleTableSize); | |
this->debug = 0; | |
result = KCodeSet::CheckAndMap( | |
this->codeSet, | |
&this->pgTable, | |
this->capability.kernelFlags & 0xF00, | |
(this->capability.kernelFlags & 0x1000) != 0); | |
if ( result >= 0 ) | |
return 0; | |
} | |
return result; | |
} | |
//----- (FFF0CF78) -------------------------------------------------------- | |
Result __fastcall KProcess::UnbindUserInterruptEventChecked( | |
KProcess *this, | |
KInterruptEvent *interruptEvent, | |
u32 interruptId) | |
{ | |
Result result; // r0 | |
result = KInterruptManager::UnbindUserInterruptEventChecked(&g_interruptManager, interruptEvent, interruptId); | |
if ( result >= 0 ) | |
this->boundIrqIds[interruptId >> 5] &= ~(1 << (interruptId & 0x1F)); | |
return result; | |
} | |
//----- (FFF0CFBC) -------------------------------------------------------- | |
BOOL __fastcall KProcess::IsDebugged(KProcess *this) | |
{ | |
return this->debug != 0; | |
} | |
//----- (FFF0CFCC) -------------------------------------------------------- | |
Result __fastcall KProcess::SetResourceLimits(KProcess *this, KResourceLimit *reslimit) | |
{ | |
ResourceLimitType v2; // r5 | |
s64 *currentResLimitValues; // r6 | |
Result result; // r0 | |
bool v7; // zf | |
s32 CurrentValue; // r0 | |
s64 *v9; // r2 | |
KLightMutex *p_mutex; // r0 | |
unsigned int v11; // r2 | |
bool v12; // zf | |
unsigned int v13; // r3 | |
s32 TotalCommittedMemory; // r9 | |
BOOL v15; // r5 | |
int v16; // r5 | |
u32 v17; // r0 | |
int v18; // r5 | |
u32 v19; // r0 | |
int v20; // r5 | |
u32 v21; // r0 | |
int v22; // r5 | |
u32 v23; // r0 | |
int v24; // r5 | |
u32 v25; // r0 | |
int v26; // r5 | |
u32 v27; // r0 | |
ResourceLimitType i; // r4 | |
s32 v29; // r0 | |
s64 v30[10]; // [sp+0h] [bp-70h] BYREF | |
s32 outNumThreads; // [sp+50h] [bp-20h] BYREF | |
result = (Result)this->reslimit; | |
v7 = result == 0; | |
if ( result ) | |
{ | |
result = 0xD8A093F9; | |
} | |
else | |
{ | |
v2 = RESLIMIT_PRIORITY; | |
currentResLimitValues = v30; | |
} | |
if ( v7 ) | |
{ // note how attaching the reslimit to a process does not | |
// increment the reslimit's refcount (!!) | |
do | |
{ | |
CurrentValue = KResourceLimit::GetCurrentValue(reslimit, v2); | |
v9 = ¤tResLimitValues[v2++]; | |
*v9 = CurrentValue; | |
} | |
while ( (unsigned int)v2 < RESLIMIT_MAX ); | |
p_mutex = &this->pgTable.mutex; | |
v11 = __ldrex((unsigned int *)&this->pgTable); | |
v12 = v11 == 0; | |
if ( v11 ) | |
v13 = __strex(v11, (unsigned int *)p_mutex); | |
else | |
v13 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)p_mutex); | |
if ( !v11 ) | |
v12 = v13 == 0; | |
if ( !v12 ) | |
KLightMutex::LockImpl(p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
TotalCommittedMemory = KMemoryBlockManager::GetTotalCommittedMemory(&this->pgTable.memoryBlockMgr); | |
__mcr(15, 0, 0, 7, 10, 5); | |
this->pgTable.mutex.lockingThread = 0; | |
if ( this->pgTable.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&this->pgTable.mutex); | |
v15 = KResourceLimit::Reserve(reslimit, RESLIMIT_COMMIT, TotalCommittedMemory); | |
KProcess::DumpThreadIds(this, &outNumThreads, 0, 0); | |
v16 = v15 & KResourceLimit::Reserve(reslimit, RESLIMIT_THREAD, outNumThreads); | |
v17 = KObjectAllocator::CountObjectsOwnedByProcess(&g_eventAllocator, this); | |
v18 = v16 & KResourceLimit::Reserve(reslimit, RESLIMIT_EVENT, v17); | |
v19 = KObjectAllocator::CountObjectsOwnedByProcess(&g_mutexAllocator, this); | |
v20 = v18 & KResourceLimit::Reserve(reslimit, RESLIMIT_MUTEX, v19); | |
v21 = KObjectAllocator::CountObjectsOwnedByProcess(&g_semaphoreAllocator, this); | |
v22 = v20 & KResourceLimit::Reserve(reslimit, RESLIMIT_SEMAPHORE, v21); | |
v23 = KObjectAllocator::CountObjectsOwnedByProcess(&g_timerAllocator, this); | |
v24 = v22 & KResourceLimit::Reserve(reslimit, RESLIMIT_TIMER, v23); | |
v25 = KObjectAllocator::CountObjectsOwnedByProcess(&g_sharedMemoryAllocator, this); | |
v26 = v24 & KResourceLimit::Reserve(reslimit, RESLIMIT_SHAREDMEMORY, v25); | |
v27 = KObjectAllocator::CountObjectsOwnedByProcess(&g_addressArbiterAllocator, this); | |
if ( (KResourceLimit::Reserve(reslimit, RESLIMIT_ADDRESSARBITER, v27) & v26) != 0 ) | |
{ | |
result = 0; | |
this->reslimit = reslimit; | |
} | |
else | |
{ | |
for ( i = RESLIMIT_PRIORITY; (unsigned int)i < RESLIMIT_MAX; ++i ) | |
{ | |
v29 = KResourceLimit::GetCurrentValue(reslimit, i);// not sure what the point is here... | |
KResourceLimit::Release(reslimit, i, v29); | |
KResourceLimit::Reserve(reslimit, i, currentResLimitValues[i]); | |
} | |
return 0xD8609013; | |
} | |
} | |
return result; | |
} | |
// FFF0D000: variable 'v2' is possibly undefined | |
// FFF0D004: variable 'currentResLimitValues' is possibly undefined | |
//----- (FFF0D1E0) -------------------------------------------------------- | |
Result __fastcall KProcess::Run(KProcess *this, u32 mainThreadPrio, u32 mainThreadStackSize) | |
{ | |
KResourceLimit *reslimit; // r4 | |
bool v6; // r6 | |
KResourceLimit *v8; // r0 | |
Result v9; // r0 | |
bool v10; // zf | |
Result v11; // r5 | |
bool v12; // zf | |
KThread *v13; // r0 | |
KThread *v14; // r9 | |
KThread *v15; // r0 | |
unsigned __int8 *p_state; // r0 | |
bool v17; // zf | |
reslimit = this->reslimit; | |
if ( reslimit ) | |
v6 = KResourceLimit::Reserve(this->reslimit, RESLIMIT_THREAD, 1); | |
else | |
v6 = KPROCSTATE_RUNNING; | |
if ( !v6 ) | |
return 0xC860180C; | |
v8 = this->reslimit; | |
if ( v8 && !KResourceLimit::Reserve(v8, RESLIMIT_COMMIT, mainThreadStackSize) ) | |
{ | |
v11 = 0xC860180A; | |
v12 = reslimit == 0; | |
if ( reslimit ) | |
v12 = !v6; | |
if ( v12 ) | |
return v11; | |
LABEL_12: | |
KResourceLimit::Release(reslimit, RESLIMIT_THREAD, 1); | |
return v11; | |
} | |
v9 = KPageTable::Operate( | |
&this->pgTable, | |
0x10000000 - mainThreadStackSize, | |
mainThreadStackSize >> 12, | |
0, | |
KMEMSTATE_LOCKED, | |
KMEMPERM_KRW_RW, | |
KMEMUPDATE_NONE, | |
this->capability.kernelFlags & 0xF00); | |
if ( v9 < 0 ) | |
{ | |
v10 = reslimit == 0; | |
v11 = v9; | |
if ( reslimit ) | |
v10 = !v6; | |
if ( v10 ) | |
return v11; | |
goto LABEL_12; | |
} | |
v13 = (KThread *)KSlabHeap::Allocate(&g_threadAllocator.slabHeap); | |
v14 = v13; | |
if ( v13 ) | |
{ | |
v15 = (KThread *)KSynchronizationObject::KSynchronizationObject(v13); | |
v15->KTimerTask::next = 0; | |
v15->KWorkerTask::next = 0; | |
v15->KSynchronizationObject::KAutoObject::__vftable = &KThread::vt; | |
v15->KTimerTask::__vftable = &KThread::vt_KTimerTask; | |
v15->KInterruptTask::next = 0; | |
v15->KWorkerTask::__vftable = &KThread::vt_KWorkerTask; | |
v15->KInterruptTask::KInterruptHandler::__vftable = &KThread::vt_KInterruptTask; | |
v15->shallTerminate = 0; | |
v15->wantedLightMutex = 0; | |
v15->synchronizationResult = 0xE7E3FFFF; | |
v15->syncObjectWaitAllList.link.next = (KSynchronizationObjectLinkedListNode *)&v15->syncObjectWaitAllList.link; | |
v15->syncObjectWaitAllList.count = 0; | |
v15->syncObjectWaitAllList.link.prev = (KSynchronizationObjectLinkedListNode *)&v15->syncObjectWaitAllList.link; | |
v15->heldMutexListRootNode = 0; | |
v15->mutexTryingToAcquireList.link.next = (KMutexLinkedListNode *)&v15->mutexTryingToAcquireList.link; | |
v15->mutexTryingToAcquireList.count = 0; | |
v15->mutexTryingToAcquireList.link.prev = (KMutexLinkedListNode *)&v15->mutexTryingToAcquireList.link; | |
v15->affinityMask = 0; | |
v15->owner = 0; | |
v15->context = 0; | |
KAutoObject::Initialize(v14); | |
} | |
this->mainThread = v14; | |
if ( !v14 ) | |
{ | |
v11 = 0xC8601803; | |
v17 = reslimit == 0; | |
if ( reslimit ) | |
v17 = !v6; | |
if ( v17 ) | |
return v11; | |
goto LABEL_12; | |
} | |
KThread::InitializeUserThread( | |
this->mainThread, | |
this->codeSet->text.baseUserVa, | |
0, | |
0x10000000u, | |
mainThreadPrio, | |
-2, | |
this); | |
KObjectAllocator::Register(&g_threadAllocator, this->mainThread); | |
p_state = (unsigned __int8 *)&this->state; | |
do | |
__ldrex(p_state); | |
while ( __strex(KPROCSTATE_RUNNING, p_state) ); | |
KThread::PrepareToRun(this->mainThread); | |
return 0; | |
} | |
// FFF0D310: conditional instruction was optimized away because r0.4!=0 | |
// FFF0D400: conditional instruction was optimized away because zf.1==1 | |
//----- (FFF0D460) -------------------------------------------------------- | |
Result __fastcall KProcess::BindUserInterruptEvent( | |
KProcess *this, | |
KInterruptEvent *interruptEvent, | |
u32 irqId, | |
s32 coreId, | |
s32 priority, | |
bool levelSensitive) | |
{ | |
Result result; // r0 | |
if ( irqId >= 0x80 || ((this->capability.irqAcl[irqId >> 5] >> (irqId & 0x1F)) & 1) == 0 ) | |
return 0xD92007EA; | |
result = KInterruptManager::BindUserInterruptEvent( | |
&g_interruptManager, | |
interruptEvent, | |
irqId, | |
coreId, | |
priority, | |
1, | |
levelSensitive); | |
if ( result >= 0 ) | |
this->boundIrqIds[irqId >> 5] |= 1 << (irqId & 0x1F); | |
return result; | |
} | |
//----- (FFF0D4EC) -------------------------------------------------------- | |
void __fastcall KDebug::DoWorkerTask(KWorkerTask *__shifted(KDebug,0x14) this) | |
{ | |
KProcess::TerminateOtherProcess(ADJ(this)->process); | |
} | |
//----- (FFF0D4F4) -------------------------------------------------------- | |
Result __fastcall KProcess::TerminateOtherProcess(KProcess *this) | |
{ | |
unsigned __int8 *p_state; // r1 | |
KProcess::SetDebugTerminatedFlag(this); | |
if ( KProcess::TerminateImpl1(this) ) | |
{ | |
p_state = (unsigned __int8 *)&this->state; | |
do | |
__ldrex(p_state); | |
while ( __strex(KPROCSTATE_TERMINATED, p_state) ); | |
KSynchronizationObject::NotifyWaiters(this, 0); | |
this->DecrementRefcount(this); | |
} | |
return 0; | |
} | |
//----- (FFF0D554) -------------------------------------------------------- | |
void __fastcall SetEightBytesTo1(bool *statusArray, bool isFree) | |
{ | |
int v2; // r1 | |
v2 = isFree | (isFree << 8) | ((isFree | (isFree << 8)) << 16); | |
*(_DWORD *)statusArray = v2; | |
*((_DWORD *)statusArray + 1) = v2; | |
} | |
//----- (FFF0D56C) -------------------------------------------------------- | |
// local variable allocation has failed, the output may be wrong! | |
KFiqState __fastcall KFiqState::CompareExchangeStrong(KFiqState *this, KFiqState oldVal, KFiqState newVal) | |
{ | |
int v3; // r3 | |
unsigned int v4; // r1 | |
unsigned __int8 v5; // r2 | |
v4 = oldVal & 0xFFFF00FF | v3 & 0xFFFF0000 | (unsigned __int16)((_WORD)newVal << 8); | |
while ( 1 ) | |
{ | |
v5 = __ldrex((unsigned __int8 *)this); | |
v4 = v4 & 0xFF00FFFF | (v5 << 16) & 0xFF0000; | |
if ( v5 != (unsigned __int8)v4 ) | |
break; | |
if ( !__strex(v4 << 16 >> 24, (unsigned __int8 *)this) ) | |
return v4 << 8 >> 24; | |
} | |
__clrex(); | |
return v4 << 8 >> 24; | |
} | |
// FFF0D56C: variables would overlap: r2.1 and r2.2 | |
//----- (FFF0D5D4) -------------------------------------------------------- | |
void __fastcall KFiqState::Set(KFiqState *this, KFiqState newState) | |
{ | |
do | |
__ldrex((unsigned __int8 *)this); | |
while ( __strex(newState, (unsigned __int8 *)this) ); | |
} | |
//----- (FFF0D5FC) -------------------------------------------------------- | |
KInterruptEvent *__fastcall KHandleTable::ConvertToInterruptEvent(KHandleTable *this, Handle handle) | |
{ | |
KInterruptEvent *result; // r0 | |
KInterruptEvent *v3; // r4 | |
unsigned __int8 v4; // r6 | |
int v5; // r1 | |
KInterruptEvent *v6; // r5 | |
_BYTE v7[8]; // [sp+0h] [bp-20h] BYREF | |
char v8; // [sp+8h] [bp-18h] BYREF | |
int v9; // [sp+Ch] [bp-14h] | |
result = (KInterruptEvent *)KHandleTable::ConvertToAutoObject(this, handle); | |
v3 = result; | |
if ( result ) | |
{ | |
result->GetTypeObj((KTypeObj *)v7, result); | |
v4 = v7[4]; | |
v3->GetTypeObj((KTypeObj *)&v8, v3); | |
v5 = v4 | 3; | |
if ( v5 == (unsigned __int8)v9 ) | |
v6 = v3; | |
else | |
v6 = 0; | |
if ( v5 != (unsigned __int8)v9 ) | |
v3->DecrementRefcount(v3); | |
return v6; | |
} | |
return result; | |
} | |
//----- (FFF0D684) -------------------------------------------------------- | |
void __fastcall KThreadContext::LoadVfp(KThreadContext *ctx) | |
{ | |
_R1 = ctx->fpscr; | |
__asm { VMSR FPSCR, R1 } | |
} | |
//----- (FFF0D698) -------------------------------------------------------- | |
bool __fastcall KScheduler::RemoveTerminatingThread(KScheduler *this, KThread *thread) | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( (thread->schedulingMask & 0xF) == KTHREADSCHEDSTAT_RUNNING ) | |
KScheduler::RemoveThread(this, thread, thread->dynamicPriority); | |
thread->alive = 0; | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 1; | |
} | |
//----- (FFF0D6E8) -------------------------------------------------------- | |
Result __fastcall KScheduler::ChangeAppPreemptionMode(u32 newMode) | |
{ | |
Result v2; // r4 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( g_schedulerAppPreemptionMode == newMode ) | |
goto LABEL_6; | |
v2 = 0xC8A01414; | |
if ( !g_cpuTimeLimiterMode0.active && !g_cpuTimeLimiterMode1.active ) | |
{ | |
g_schedulerAppPreemptionMode = newMode; | |
LABEL_6: | |
v2 = 0; | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return v2; | |
} | |
//----- (FFF0D75C) -------------------------------------------------------- | |
void __fastcall KScheduler::YieldCurrentThread(KScheduler *this) | |
{ | |
KThread *volatile curThread; // r5 | |
unsigned __int32 prio; // r1 | |
KThreadIntrusiveLink *p_link; // r0 | |
KThread *next; // r3 | |
KThread *prev; // r1 | |
KThread *v7; // r12 | |
KThreadIntrusiveLink *v8; // r7 | |
s32 dynamicPriority; // r0 | |
int coreId; // r8 | |
KThreadIntrusiveList *v11; // r1 | |
KThreadIntrusiveLink *v12; // r12 | |
BOOL v13; // r9 | |
KThreadIntrusiveLink *v14; // r10 | |
int v15; // r2 | |
unsigned int CPSR; // r5 | |
curThread = current.clc.current.thread; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
prio = curThread->dynamicPriority; | |
p_link = &this->threadsByPrio[prio].link; | |
next = this->threadsByPrio[prio].link.next; | |
if ( next && next == p_link->prev ) | |
this->prioBitfield[prio >> 5] &= ~(0x80000000 >> (prio & 0x1F));// no more threads with that priority | |
__mcr(15, 0, 0, 7, 10, 5); | |
prev = curThread->link.prev; | |
v7 = curThread->link.next; | |
if ( prev ) | |
v8 = &prev->link; | |
else | |
v8 = p_link; | |
if ( v7 ) | |
p_link = &v7->link; | |
v8->next = v7; | |
p_link->prev = prev; | |
--this->numThreads; // remove thread | |
if ( g_coreLocalRegions[this->coreId].clc.current.thread == curThread )// almost always true except on rare occurences just after creation? | |
this->reschedule = 1; | |
dynamicPriority = curThread->dynamicPriority; // and now insert it back | |
coreId = this->coreId; | |
v11 = &this->threadsByPrio[dynamicPriority]; | |
v12 = (KThreadIntrusiveLink *)v11->link.prev; | |
v13 = this->threadsByPrio[dynamicPriority].link.next == 0; | |
if ( v11->link.prev ) | |
v14 = v12 + 20; | |
else | |
v14 = &this->threadsByPrio[dynamicPriority].link; | |
curThread->link.next = 0; | |
curThread->link.prev = (KThread *)v12; | |
v14->next = curThread; | |
v11->link.prev = curThread; | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( v13 ) | |
this->prioBitfield[(unsigned int)dynamicPriority >> 5] |= 0x80000000 >> (dynamicPriority & 0x1F); | |
v15 = this->coreId; | |
++this->numThreads; | |
if ( v15 != coreId || current.clc.current.thread->dynamicPriority > dynamicPriority ) | |
this->reschedule = 1; | |
this->disableCount = 2; | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
this->disableCount = 0; | |
this->reschedule = 1; | |
KScheduler::SwitchThread(this, 0); | |
__set_CPSR(CPSR); | |
} | |
//----- (FFF0D8DC) -------------------------------------------------------- | |
void __fastcall KScheduler::InitializeNewThread(KScheduler *this, KThread *thread) | |
{ | |
u32 coreId; // r1 | |
signed __int32 idealProcessor; // r1 | |
signed __int32 i; // r4 | |
int v7; // r0 | |
signed __int32 v8; // r1 | |
int v9; // r0 | |
KAffinityMask affinityMask; // [sp+0h] [bp-18h] BYREF | |
KSchedulerLock::Lock(&g_schedulerLock); | |
coreId = thread->coreId; | |
thread->alive = 1; | |
if ( coreId == -1 ) | |
{ | |
affinityMask = thread->affinityMask; | |
idealProcessor = thread->idealProcessor; | |
if ( idealProcessor >= 0 && KAffinityMask::CheckCoreAllowed(&affinityMask, idealProcessor) ) | |
{ | |
i = thread->idealProcessor; | |
} | |
else | |
{ | |
for ( i = 0; ; ++i ) | |
{ | |
v7 = (MPCORE.scu.cfgr & 3) + 1; | |
if ( v7 <= i ) | |
kernelpanic(); | |
if ( KAffinityMask::CheckCoreAllowed(&affinityMask, i) ) | |
break; | |
} | |
} | |
v8 = thread->coreId; | |
thread->coreId = i; | |
if ( v8 >= 0 ) | |
{ | |
v9 = (MPCORE.scu.cfgr & 3) + 1; | |
if ( v9 > v8 ) | |
KVfpRegisterDumpHelper::DumpAndDisableVfpRegsForThread(thread, v8); | |
} | |
} | |
if ( (thread->schedulingMask & 0xF) == KTHREADSCHEDSTAT_RUNNING ) | |
KScheduler::AddThread(this, thread); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
//----- (FFF0D9C8) -------------------------------------------------------- | |
void __fastcall KSemaphore::Initialize(KSemaphore *this, KProcess *ownerProcess, s32 initialCount, s32 maxCount) | |
{ | |
unsigned int *p_count; // r0 | |
KAutoObject::IncrementRefcount(ownerProcess); | |
p_count = (unsigned int *)&this->count; | |
this->ownerProcess = ownerProcess; | |
do | |
__ldrex(p_count); | |
while ( __strex(initialCount, p_count) ); | |
this->maxCount = maxCount; | |
} | |
//----- (FFF0DA04) -------------------------------------------------------- | |
Result __fastcall KSemaphore::Release(KSemaphore *this, s32 *outCount, s32 releaseCount) | |
{ | |
unsigned int *p_count; // r3 | |
s32 maxCount; // r12 | |
s32 v6; // r4 | |
Result result; // r0 | |
p_count = (unsigned int *)&this->count; | |
maxCount = this->maxCount; | |
do | |
{ | |
v6 = __ldrex(p_count); | |
if ( v6 + releaseCount > maxCount ) | |
{ | |
__clrex(); | |
return 0xD8E007FD; | |
} | |
} | |
while ( __strex(v6 + releaseCount, p_count) ); | |
KSynchronizationObject::NotifyWaiters(this, 0); | |
result = 0; | |
*outCount = v6; | |
return result; | |
} | |
//----- (FFF0DA54) -------------------------------------------------------- | |
Result __fastcall KClientPort::CreateSession(KClientPort *this, KClientSession **outClientSessionPtr) | |
{ | |
int maxSessionCount; // r2 | |
unsigned __int16 *p_currentSessionCount; // r0 | |
signed __int16 v6; // r1 | |
KSession *v7; // r0 | |
KSession *v8; // r4 | |
KSession *v9; // r0 | |
KServerSession *__shifted(KSession,8) v10; // r0 | |
KClientSession *v11; // r0 | |
unsigned __int16 *v12; // r1 | |
unsigned __int16 v14; // r0 | |
maxSessionCount = this->maxSessionCount; | |
p_currentSessionCount = (unsigned __int16 *)&this->currentSessionCount; | |
do | |
{ | |
v6 = __ldrex(p_currentSessionCount); | |
if ( v6 >= maxSessionCount ) | |
{ | |
__clrex(); | |
return 0xD0401834; | |
} | |
} | |
while ( __strex(v6 + 1, p_currentSessionCount) ); | |
v7 = (KSession *)KSlabHeap::Allocate(&g_sessionAllocator.slabHeap); | |
v8 = v7; | |
if ( v7 ) | |
{ | |
v9 = (KSession *)KAutoObject::KAutoObject(v7); | |
v9->__vftable = &KSession::vt; | |
v10 = (KServerSession *__shifted(KSession,8))KSynchronizationObject::KSynchronizationObject(&v9->server); | |
ADJ(v10)->server.__vftable = &KServerSession::vt; | |
ADJ(v10)->server.syncRequestWaitList.link.prev = 0; | |
ADJ(v10)->server.syncRequestWaitList.link.next = 0; | |
ADJ(v10)->server.currentRequestingThread = 0; | |
v11 = (KClientSession *)KSynchronizationObject::KSynchronizationObject(&ADJ(v10)->client); | |
v11->__vftable = &KClientSession::vt; | |
v11->status = 0; | |
KAutoObject::Initialize(v8); | |
} | |
if ( v8 ) | |
{ | |
KSession::Initialize(v8, this); | |
KObjectAllocator::Register(&g_sessionAllocator, v8); | |
KServerPort::Connect(&this->parent->server, &v8->server); | |
*outClientSessionPtr = &v8->client; | |
return 0; | |
} | |
else | |
{ | |
v12 = (unsigned __int16 *)&this->currentSessionCount; | |
do | |
v14 = __ldrex(v12); | |
while ( __strex(v14 - 1, v12) ); | |
if ( this->maxSessionCount == v14 ) | |
KSynchronizationObject::NotifyWaiters(this, 0);// client port became available | |
return 0xC8601809; | |
} | |
} | |
// FFF0DAB8: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF0DBB4) -------------------------------------------------------- | |
void __fastcall KDmaManager::AbortAll(KDmaManager *this) | |
{ | |
int i; // r4 | |
for ( i = 0; i < 8; ++i ) | |
KDmaChannel::AbortTransferForPowerStateChange(&g_dmaChannels[(char)i]); | |
KDmaController::KillManagerThread(); | |
KDmaController::ClearAllInterrupts(); | |
} | |
//----- (FFF0DBF4) -------------------------------------------------------- | |
Result __fastcall KDmaManager::CheckAndPrepareChannelRestart( | |
KDmaManager *this, | |
s8 channelId, | |
u32 dstAddr, | |
u32 srcAddr, | |
u32 size, | |
DmaRestartFlags restartFlags) | |
{ | |
int state; // r0 | |
bool v7; // zf | |
state = (unsigned __int8)g_dmaChannels[channelId].state; | |
v7 = state == KDMACHANSTATE_STARTED; | |
if ( state != KDMACHANSTATE_STARTED ) | |
v7 = state == KDMACHANSTATE_RESTARTED; | |
if ( v7 ) | |
return 0xD04007F0; // kernel9 has additional locking code here (iirc) | |
else | |
return 0; | |
} | |
//----- (FFF0DC24) -------------------------------------------------------- | |
KAutoObject *__fastcall KObjectName::FindObject(const char *name) | |
{ | |
unsigned int v2; // r2 | |
bool v3; // zf | |
unsigned int v4; // r3 | |
KObjectNameLinkedListNode *next; // r3 | |
KObjectName *objectName; // r2 | |
int v7; // r1 | |
KAutoObject *obj; // r4 | |
v2 = __ldrex((unsigned int *)&g_objectNameListMutex); | |
v3 = v2 == 0; | |
if ( v2 ) | |
v4 = __strex(v2, (unsigned int *)&g_objectNameListMutex); | |
else | |
v4 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_objectNameListMutex); | |
if ( !v2 ) | |
v3 = v4 == 0; | |
if ( !v3 ) | |
KLightMutex::LockImpl(&g_objectNameListMutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
next = g_objectNameList.link.next; | |
if ( (KObjectNameLinkedListLink *)g_objectNameList.link.next == &g_objectNameList.link ) | |
{ | |
LABEL_13: | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_objectNameListMutex.lockingThread = 0; | |
if ( g_objectNameListMutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_objectNameListMutex); | |
return 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
objectName = next->objectName; | |
v7 = 0; | |
if ( objectName->name[0] == *name ) | |
break; | |
LABEL_12: | |
next = next->link.next; | |
if ( next == (KObjectNameLinkedListNode *)&g_objectNameList.link ) | |
goto LABEL_13; | |
} | |
while ( objectName->name[v7] ) | |
{ | |
++v7; | |
if ( objectName->name[v7] != name[v7] ) | |
goto LABEL_12; | |
} | |
obj = objectName->obj; | |
KAutoObject::IncrementRefcount(obj); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_objectNameListMutex.lockingThread = 0; | |
if ( g_objectNameListMutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_objectNameListMutex); | |
return obj; | |
} | |
} | |
//----- (FFF0DD08) -------------------------------------------------------- | |
Result __fastcall KObjectName::RegisterObject(KAutoObject *obj, const char *name) | |
{ | |
KObjectName *objName; // r0 | |
KObjectName *v5; // r4 | |
unsigned int v7; // r2 | |
bool v8; // zf | |
unsigned int v9; // r3 | |
KLinkedListNode *v10; // r0 | |
objName = (KObjectName *)KSlabHeap::Allocate(&g_objectNameSlabHeap); | |
v5 = objName; | |
if ( !objName ) | |
return 0xD86007F3; | |
*(_DWORD *)objName->name = 0; | |
*(_DWORD *)&objName->name[4] = 0; | |
*(_DWORD *)&objName->name[8] = 0; | |
objName->obj = 0; | |
objName->obj = obj; | |
strncpy(objName->name, name, 0xCu); | |
v5->name[11] = 0; | |
KAutoObject::IncrementRefcount(obj); // note: there's no "unregister" method, therefore this will prevent the object from being deleted forever | |
v7 = __ldrex((unsigned int *)&g_objectNameListMutex); | |
v8 = v7 == 0; | |
if ( v7 ) | |
v9 = __strex(v7, (unsigned int *)&g_objectNameListMutex); | |
else | |
v9 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_objectNameListMutex); | |
if ( !v7 ) | |
v8 = v9 == 0; | |
if ( !v8 ) | |
KLightMutex::LockImpl(&g_objectNameListMutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
v10 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v10 ) | |
{ | |
v10->link.next = 0; | |
v10->link.prev = 0; | |
v10->data = 0; | |
} | |
v10->data = v5; | |
KLinkedList::InsertAfter((KLinkedList *)&g_objectNameList, (KLinkedListLink *)&g_objectNameList.link, v10); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_objectNameListMutex.lockingThread = 0; | |
if ( g_objectNameListMutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_objectNameListMutex); | |
return 0; | |
} | |
// FFF0DD3C: conditional instruction was optimized away because r0.4!=0 | |
// FFF0DDD0: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF0DE2C) -------------------------------------------------------- | |
KServerSession *__fastcall KServerPort::AcceptSession(KServerPort *this) | |
{ | |
KServerSessionLinkedListNode *next; // r4 | |
KServerSession *serverSession; // r6 | |
KServerSessionLinkedListNode *v5; // [sp+0h] [bp-18h] BYREF | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( this->incomingServerSessions.count ) | |
{ | |
next = this->incomingServerSessions.link.next; | |
serverSession = next->serverSession; | |
v5 = next; | |
KLinkedList::EraseNode((KLinkedList *)&this->incomingServerSessions, (KLinkedListLink **)&v5); | |
KSlabHeap::Free(&g_linkedListNodeSlabHeap, next); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return serverSession; | |
} | |
else | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
} | |
//----- (FFF0DE94) -------------------------------------------------------- | |
void __fastcall KCodeSegment::EnsureCacheCoherencyForCode(KCodeSegment *this) | |
{ | |
KBlockInfoLinkedListNode *node; // r4 | |
KBlockInfo *blockInfo; // r0 | |
u32 baseAddress; // r7 | |
u32 v5; // r6 | |
for ( node = this->pgGroup.list.link.next; | |
node != (KBlockInfoLinkedListNode *)&this->pgGroup.list.link; | |
node = node->link.next ) | |
{ | |
blockInfo = node->blockInfo; | |
baseAddress = blockInfo->baseAddress; | |
v5 = blockInfo->numPages << 12; | |
KPageTable::CleanInvalidateDataCacheRange(blockInfo->baseAddress, v5); | |
KPageTable::CleanInvalidateInstructionCacheRange(baseAddress, v5); | |
} | |
} | |
//----- (FFF0DEE0) -------------------------------------------------------- | |
KCodeSegment *__fastcall KCodeSegment::KCodeSegment(KCodeSegment *this) | |
{ | |
this->baseUserVa = 0; | |
this->totalNumPages = 0; | |
return CONTAINING_RECORD(KPageGroup::KPageGroup(&this->pgGroup), KCodeSegment, pgGroup); | |
} | |
//----- (FFF0DF00) -------------------------------------------------------- | |
Result __fastcall KHandleTable::Initialize(KHandleTable *this, s32 handleTableSize) | |
{ | |
unsigned int v4; // r2 | |
bool v5; // zf | |
unsigned int v6; // r3 | |
KHandleTableEntry *Contiguous; // r10 | |
unsigned int v8; // r2 | |
Result result; // r0 | |
int i; // r0 | |
KHandleTableEntry *v11; // r1 | |
KHandleTableEntry *v12; // r1 | |
if ( (unsigned int)handleTableSize <= 0x28 ) | |
{ | |
if ( handleTableSize <= 0 ) | |
LOWORD(handleTableSize) = 40; | |
this->entries = this->internalTable; | |
this->handleTableSize = handleTableSize; | |
goto LABEL_25; | |
} | |
v4 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v5 = v4 == 0; | |
if ( v4 ) | |
v6 = __strex(v4, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v6 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v4 ) | |
v5 = v6 == 0; | |
if ( !v5 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
Contiguous = (KHandleTableEntry *)KPageHeap::AllocateContiguous( | |
&g_memoryManager.baseHeap, | |
(unsigned int)(8 * handleTableSize + 4095) >> 12, | |
0); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
if ( !Contiguous ) | |
return 0xD86007F3; | |
v8 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( v8 ) | |
{ | |
__strex(v8, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
} | |
else if ( !__strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex) ) | |
{ | |
goto LABEL_16; | |
} | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
LABEL_16: | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)Contiguous, (unsigned int)(8 * handleTableSize + 4095) >> 12); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
this->entries = Contiguous; | |
this->handleTableSize = handleTableSize; | |
LABEL_25: | |
this->nextId = 1; | |
this->count = 0; | |
this->maxCount = 0; | |
for ( i = 0; this->handleTableSize - 1 > i; ++i ) | |
{ | |
v11 = &this->entries[i]; | |
v11->used.info = (u32)&this->entries[i + 1]; | |
v11->used.object = 0; | |
} | |
result = 0; | |
v12 = &this->entries[this->handleTableSize - 1]; | |
v12->used.object = 0; | |
v12->used.info = 0; | |
this->firstFreeEntry = this->entries; | |
return result; | |
} | |
//----- (FFF0E148) -------------------------------------------------------- | |
void __fastcall KProcess::ChangeAffinityMask(u8 *newAffMask, u8 affMask, bool add) | |
{ | |
bool v3; // zf | |
u8 v4; // r2 | |
int v5; // r1 | |
u8 v6; // r1 | |
v3 = !add; | |
v4 = *newAffMask; | |
v5 = 1 << affMask; | |
if ( v3 ) | |
v6 = v4 & ~(_BYTE)v5; | |
else | |
v6 = v5 | v4; | |
*newAffMask = v6; | |
} | |
//----- (FFF0E168) -------------------------------------------------------- | |
void __fastcall KAffinityMask::MakeAllCoresMask(KAffinityMask *result) | |
{ | |
char cfgr; // r1 | |
cfgr = MPCORE.scu.cfgr; | |
*result = ~(-1 << ((cfgr & 3) + 1)); | |
} | |
//----- (FFF0E18C) -------------------------------------------------------- | |
Result __fastcall KSharedMemory::Initialize( | |
KSharedMemory *this, | |
KProcess *ownerProcess, | |
u32 addr, | |
u32 size, | |
u32 ownerPerms, | |
u32 othersPerms) | |
{ | |
unsigned __int8 *p_sharedMemMapRefcount; // r0 | |
u32 numPages; // r7 | |
u32 v12; // r0 | |
bool v13; // zf | |
KResourceLimit *reslimit; // r8 | |
u32 kernelFlags; // r0 | |
unsigned int v16; // r2 | |
bool v17; // zf | |
unsigned int v18; // r3 | |
int v19; // r0 | |
void *Contiguous; // r11 | |
KPageHeapBlock *next; // r5 | |
unsigned int *p_kernAllocatedForProcess; // r0 | |
unsigned int v23; // r1 | |
unsigned __int8 *v24; // r0 | |
int v25; // r7 | |
bool v27; // zf | |
unsigned __int8 *v28; // r0 | |
KPageHeapBlock *ContiguousBackwards; // r0 | |
unsigned __int8 *v30; // r0 | |
u32 v31; // [sp+8h] [bp-40h] | |
__int16 newPerms; // [sp+Ch] [bp-3Ch] | |
KProcessPageTable *addra; // [sp+10h] [bp-38h] | |
u32 addr_4; // [sp+14h] [bp-34h] | |
KPageGroup pgGrp; // [sp+18h] [bp-30h] BYREF | |
this->othersPerms = othersPerms; | |
this->ownerPerms = ownerPerms; | |
this->ownerProcess = ownerProcess; | |
this->isDeviceSharedMem = 0; | |
p_sharedMemMapRefcount = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
__ldrex(p_sharedMemMapRefcount); | |
while ( __strex(0xFFu, p_sharedMemMapRefcount) ); | |
numPages = (size + 4095) >> 12; | |
this->transferMemAddress = addr; | |
if ( addr ) | |
{ | |
addra = &ownerProcess->pgTable; | |
v12 = ((__int64)current.clc.current.process->codeSet->titleId >> 8) & 0xFFFFF; | |
v13 = v12 == 0x36E; // Skylanders: Spyros Adventure (us, eu) | |
if ( v12 != 0x36E ) | |
v13 = v12 == 0x4C0; | |
if ( v13 && size == 0x2000 ) | |
goto LABEL_54; | |
v27 = v12 == 0x531; // VectorRacing (jp, us) | |
if ( v12 != 0x531 ) | |
v27 = v12 == 0x8B8; | |
if ( v27 && size == 0x14000 ) | |
{ | |
LABEL_54: | |
this->workaround = 1; | |
addr_4 = addr + (numPages << 12) - 4096; | |
if ( KPageTable::AnalyzeRange(addra, &this->pgGrp, addr, numPages - 1) < 0 )// | |
// | |
// skylanders/vectorracing workaround: | |
// | |
// - sharedmem is: <all but last page> + a freshly allocated page | |
// - last page (which is not actually part of the shardmem) is reprotected back to rw | |
kernelpanic(); | |
if ( KPageTable::CheckAndChangeGroupStateAndPerms( | |
addra, | |
addr, | |
&this->pgGrp, | |
KMEMSTATE_FLAGS_ANY, | |
KMEMSTATE_PRIVATE_DATA, | |
KMEMPERM_KRW_RW, | |
KMEMSTATE_LOCKED, | |
(KMemoryPermission)(ownerPerms | KMEMPERM_KRW)) < 0 ) | |
kernelpanic(); | |
KPageGroup::KPageGroup(&pgGrp); | |
if ( KPageTable::AnalyzeRange(addra, &pgGrp, addr_4, 1u) < 0 ) | |
kernelpanic(); | |
v25 = KPageTable::CheckAndChangeGroupStateAndPerms( | |
addra, | |
addr_4, | |
&pgGrp, | |
KMEMSTATE_FLAGS_ANY, | |
KMEMSTATE_PRIVATE_DATA, | |
KMEMPERM_KRW_RW, | |
KMEMSTATE_LOCKED, | |
KMEMPERM_KRW_RW); | |
if ( v25 < 0 ) | |
kernelpanic(); | |
KPageGroup::EraseAll(&pgGrp); | |
ContiguousBackwards = KMemoryManager::AllocateContiguousBackwards(&g_memoryManager, 1u, MEMOP_REGION_BASE); | |
if ( !ContiguousBackwards ) | |
kernelpanic(); | |
KPageGroup::AddRange(&this->pgGrp, (u32)ContiguousBackwards, ContiguousBackwards->numPages); | |
KPageGroup::~KPageGroup(&pgGrp); | |
KPageGroup::IncrefPages(&this->pgGrp); | |
KAutoObject::IncrementRefcount(this->ownerProcess); | |
v30 = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
__ldrex(v30); | |
while ( __strex(1u, v30) ); | |
} | |
else | |
{ // no workaround | |
v25 = KPageTable::AnalyzeRange(addra, &this->pgGrp, addr, (size + 4095) >> 12); | |
if ( v25 >= 0 ) | |
{ | |
v25 = KPageTable::CheckAndChangeGroupStateAndPerms( | |
addra, | |
addr, | |
&this->pgGrp, | |
KMEMSTATE_FLAGS_ANY, | |
KMEMSTATE_PRIVATE_DATA, | |
KMEMPERM_KRW_RW, | |
KMEMSTATE_LOCKED, | |
(KMemoryPermission)(ownerPerms | KMEMPERM_KRW)); | |
if ( v25 >= 0 ) | |
{ | |
KPageGroup::IncrefPages(&this->pgGrp); | |
KAutoObject::IncrementRefcount(this->ownerProcess); | |
v28 = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
__ldrex(v28); | |
while ( __strex(1u, v28) ); | |
} | |
} | |
} | |
return v25; | |
} | |
if ( numPages ) // sharedmem, alloc new pages | |
// applications are not allowed to do this | |
{ | |
reslimit = ownerProcess->reslimit; | |
if ( reslimit ) | |
v31 = KResourceLimit::Reserve(reslimit, RESLIMIT_COMMIT, numPages << 12) | othersPerms & 0xFFFFFF00; | |
else | |
LOBYTE(v31) = 1; | |
kernelFlags = ownerProcess->capability.kernelFlags; | |
if ( (kernelFlags & 0x40) == 0 ) // NOT "shared device memory" flag | |
{ | |
next = KMemoryManager::AllocateContiguousBackwards(&g_memoryManager, (size + 4095) >> 12, MEMOP_REGION_BASE); | |
if ( next ) | |
{ | |
do | |
{ | |
KPageGroup::AddRange(&this->pgGrp, (u32)next, next->numPages); | |
next = next->link.next; | |
} | |
while ( next ); | |
goto LABEL_36; | |
} | |
if ( reslimit && (_BYTE)v31 ) | |
LABEL_26: | |
KResourceLimit::Release(reslimit, RESLIMIT_COMMIT, numPages << 12); | |
return 0xD86007F3; | |
} | |
newPerms = kernelFlags & 0xF00; | |
v16 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v17 = v16 == 0; | |
if ( v16 ) | |
v18 = __strex(v16, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v18 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v16 ) | |
v17 = v18 == 0; | |
if ( !v17 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
v19 = newPerms & 0xF00; | |
switch ( v19 ) | |
{ | |
case MEMOP_REGION_APPLICATION: | |
Contiguous = KPageHeap::AllocateContiguous(&g_memoryManager.applicationHeap, (size + 4095) >> 12, 0); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters <= 0 ) | |
goto LABEL_32; | |
break; | |
case MEMOP_REGION_SYSTEM: | |
Contiguous = KPageHeap::AllocateContiguous(&g_memoryManager.systemHeap, (size + 4095) >> 12, 0); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters <= 0 ) | |
goto LABEL_32; | |
break; | |
case MEMOP_REGION_BASE: | |
Contiguous = KPageHeap::AllocateContiguous(&g_memoryManager.baseHeap, (size + 4095) >> 12, 0); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters <= 0 ) | |
{ | |
LABEL_32: | |
if ( Contiguous ) | |
{ | |
KPageGroup::AddRange(&this->pgGrp, (u32)Contiguous, (size + 4095) >> 12); | |
this->isDeviceSharedMem = 1; | |
goto LABEL_36; | |
} | |
if ( reslimit && (_BYTE)v31 ) | |
goto LABEL_26; | |
return 0xD86007F3; | |
} | |
break; | |
default: | |
kernelpanic(); | |
} | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
goto LABEL_32; | |
} | |
LABEL_36: | |
p_kernAllocatedForProcess = &ownerProcess->kernAllocatedForProcess; | |
do | |
v23 = __ldrex(p_kernAllocatedForProcess); | |
while ( __strex(v23 + size, p_kernAllocatedForProcess) ); | |
KPageGroup::IncrefPages(&this->pgGrp); | |
KAutoObject::IncrementRefcount(this->ownerProcess); | |
v24 = (unsigned __int8 *)&this->sharedMemMapRefcount; | |
do | |
__ldrex(v24); | |
while ( __strex(1u, v24) ); | |
return 0; | |
} | |
// FFF0E2E8: conditional instruction was optimized away because %newPerms.4<F01u | |
//----- (FFF0E71C) -------------------------------------------------------- | |
KSharedMemory *__fastcall KSharedMemory::KSharedMemory(KSharedMemory *this) | |
{ | |
KSharedMemory *v1; // r0 | |
KSharedMemory *this_; // r0 | |
v1 = (KSharedMemory *)KAutoObject::KAutoObject(this); | |
v1->__vftable = &KSharedMemory::vt; | |
this_ = (KSharedMemory *)&KPageGroup::KPageGroup(&v1->pgGrp)[-1].list.link; | |
this_->ownerProcess = 0; | |
this_->ownerPerms = KMEMPERM_NONE; | |
this_->othersPerms = KMEMPERM_NONE; | |
this_->sharedMemMapRefcount = 0; | |
this_->workaround = 0; | |
return this_; | |
} | |
//----- (FFF0E754) -------------------------------------------------------- | |
s32 __fastcall KResourceLimit::GetCurrentValue(KResourceLimit *this, ResourceLimitType type) | |
{ | |
return this->currentValues[type]; | |
} | |
//----- (FFF0E760) -------------------------------------------------------- | |
KCpuTimeLimit *__fastcall KResourceLimit::GetTimeLimit(KResourceLimit *this) | |
{ | |
KResourceLimit *v1; // r4 | |
int v2; // r0 | |
v1 = this; | |
v2 = this->limitValues[RESLIMIT_CPUTIME]; | |
if ( v2 >= 10000 ) | |
return 0; | |
if ( v2 != 1000 ) | |
return &v1->timeLimit; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( g_sysmoduleReslimitSet ) | |
v1 = (KResourceLimit *)((char *)v1 + offsetof(KResourceLimit, timeLimit)); | |
if ( !g_sysmoduleReslimitSet ) | |
v1 = 0; | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return (KCpuTimeLimit *)v1; | |
} | |
//----- (FFF0E7C0) -------------------------------------------------------- | |
Result __fastcall KServerSession::SendSyncRequest(KServerSession *this, KThread *thread) | |
{ | |
Result v3; // r6 | |
KThreadIntrusiveLink *p_link; // r4 | |
KThread *prev; // r0 | |
KThreadIntrusiveLink *v7; // r2 | |
KThreadIntrusiveLink link; // r0 | |
KThreadIntrusiveLink *v9; // r2 | |
v3 = 0xE7E3FFFF; | |
if ( this->parent->client.status != KSESSIONSTATUS_NORMAL ) | |
return 0xC920181A; | |
p_link = &this->syncRequestWaitList.link; | |
thread->waiterList = &this->syncRequestWaitList; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_PAUSED); | |
prev = this->syncRequestWaitList.link.prev; | |
if ( prev ) | |
v7 = &prev->link; | |
else | |
v7 = &this->syncRequestWaitList.link; | |
thread->link.prev = prev; | |
thread->link.next = 0; | |
v7->next = thread; | |
p_link->prev = thread; | |
if ( thread->shallTerminate ) | |
{ | |
link = thread->link; | |
if ( link.prev ) | |
v9 = &link.prev->link; | |
else | |
v9 = &this->syncRequestWaitList.link; | |
if ( link.next ) | |
p_link = &link.next->link; | |
v9->next = link.next; | |
p_link->prev = link.prev; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_RUNNING); | |
thread->waiterList = 0; | |
} | |
else | |
{ | |
v3 = 0; | |
KSynchronizationObject::NotifyWaiters(this, 0);// signal the server session (so that ReplyAndReceive wakes up) | |
} | |
return v3; | |
} | |
//----- (FFF0E880) -------------------------------------------------------- | |
void __fastcall KAddressArbiter::Initialize(KAddressArbiter *this, KProcess *owner) | |
{ | |
KAutoObject::IncrementRefcount(owner); | |
this->owner = owner; | |
} | |
//----- (FFF0E89C) -------------------------------------------------------- | |
signed int __fastcall KAddressArbiter::WaitIfLessThan( | |
KAddressArbiter *this, | |
KThread *thread, | |
u32 addr, | |
s32 value, | |
bool decrement) | |
{ | |
signed int v9; // r8 | |
KThreadIntrusiveList *p_waitList; // r5 | |
KThread *prev; // r0 | |
KThreadIntrusiveLink *p_link; // r1 | |
KThreadIntrusiveLink link; // r0 | |
KThreadIntrusiveLink *v14; // r2 | |
unsigned int CPSR; // r2 | |
unsigned int par; // r0 | |
BOOL validAddr; // r0 | |
s32 v18; // r0 | |
KThreadIntrusiveLink v19; // r0 | |
KThreadIntrusiveList *v20; // r2 | |
KThreadIntrusiveLink *v21; // r3 | |
KThread *v22; // r1 | |
KThread *next; // r0 | |
KThreadIntrusiveLink *v24; // r2 | |
KThreadIntrusiveLink *v25; // r3 | |
s32 readValue[10]; // [sp+0h] [bp-28h] BYREF | |
readValue[0] = value; | |
v9 = 0; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
p_waitList = &this->waitList; | |
thread->waiterList = &this->waitList; | |
thread->arbitrationAddr = addr; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_PAUSED); | |
prev = this->waitList.link.prev; | |
if ( prev ) | |
p_link = &prev->link; | |
else | |
p_link = &this->waitList.link; | |
thread->link.prev = prev; | |
thread->link.next = 0; | |
p_link->next = thread; | |
p_waitList->link.prev = thread; | |
if ( thread->shallTerminate ) | |
{ | |
link = thread->link; | |
if ( link.prev ) | |
v14 = &link.prev->link; | |
else | |
v14 = &this->waitList.link; | |
if ( link.next ) | |
p_waitList = (KThreadIntrusiveList *)&link.next->link; | |
v14->next = link.next; | |
p_waitList->link.prev = link.prev; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_RUNNING); | |
thread->waiterList = 0; | |
} | |
else | |
{ | |
if ( decrement ) | |
{ | |
CPSR = __get_CPSR(); // exclusive ldrt/strt don't exist | |
__disable_irq(); | |
__mcr(15, 0, addr >> 12 << 12, 7, 8, 3); | |
par = __mrc(15, 0, 7, 4, 0); | |
if ( (par & 1) != 0 || !((par >> 12 << 12) | addr & 0xFFF) ) | |
{ | |
__set_CPSR(CPSR); | |
validAddr = 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
v18 = __ldrex((unsigned int *)addr); | |
if ( v18 >= value ) | |
break; | |
if ( !__strex(v18 - 1, (unsigned int *)addr) ) | |
goto LABEL_19; | |
} | |
__clrex(); | |
LABEL_19: | |
readValue[0] = v18; | |
__set_CPSR(CPSR); | |
validAddr = 1; | |
} | |
} | |
else | |
{ | |
validAddr = CopyWordFromUser(readValue, (const void *)addr); | |
} | |
if ( validAddr ) | |
{ | |
if ( readValue[0] >= value ) | |
{ | |
v19 = thread->link; | |
v20 = &this->waitList; | |
if ( v19.prev ) | |
v21 = &v19.prev->link; | |
else | |
v21 = &this->waitList.link; | |
if ( v19.next ) | |
v20 = (KThreadIntrusiveList *)&v19.next->link; | |
v21->next = v19.next; | |
v20->link.prev = v19.prev; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_RUNNING); | |
thread->waiterList = 0; | |
} | |
} | |
else | |
{ | |
v22 = thread->link.prev; | |
next = thread->link.next; | |
v24 = &this->waitList.link; | |
if ( v22 ) | |
v25 = &v22->link; | |
else | |
v25 = &this->waitList.link; | |
if ( next ) | |
v24 = &next->link; | |
v25->next = next; | |
v24->prev = v22; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_RUNNING); | |
v9 = 0xD9001814; | |
thread->waiterList = 0; | |
} | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return v9; | |
} | |
//----- (FFF0EA70) -------------------------------------------------------- | |
signed int __fastcall KAddressArbiter::WaitIfLessThanWithTimeout( | |
KAddressArbiter *this, | |
KThread *thread, | |
u32 addr, | |
s32 value, | |
bool decrement, | |
s64 timeout) | |
{ | |
signed int v8; // r9 | |
unsigned int v9; // r7 | |
int v10; // r10 | |
unsigned __int64 v11; // kr10_8 | |
KThreadIntrusiveLink *p_link; // r11 | |
KThread *prev; // r0 | |
KThreadIntrusiveLink *v14; // r1 | |
KThreadIntrusiveLink link; // r0 | |
KThreadIntrusiveLink *v16; // r2 | |
unsigned int CPSR; // r1 | |
u32 v18; // r0 | |
unsigned int v19; // lr | |
unsigned int v20; // r3 | |
BOOL validAddr; // r0 | |
KHardwareTimer *v22; // r1 | |
KThreadIntrusiveLink v23; // r0 | |
KThreadIntrusiveLink *v24; // r2 | |
KThreadIntrusiveLink *v25; // r3 | |
KThreadIntrusiveLink v26; // r0 | |
KThreadIntrusiveLink *v27; // r2 | |
KThreadIntrusiveLink *v28; // r3 | |
KThreadIntrusiveLink v29; // r0 | |
KThreadIntrusiveLink *v30; // r2 | |
KThreadIntrusiveLink *v31; // r3 | |
KTimerTask *v32; // r1 | |
KTimerTask *v33; // r1 | |
KHardwareTimer *reused; // [sp+4h] [bp-3Ch] BYREF | |
v8 = 0; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( ((((unsigned __int64)-timeout >> 32) & 0x80000000) != 0LL) != __OFSUB__( | |
0, | |
HIDWORD(timeout), | |
(_DWORD)timeout == 0) ) | |
{ | |
reused = &g_hardwareTimer; | |
v11 = __PAIR64__( | |
(((1151531653 * (unsigned __int64)(unsigned int)timeout) >> 32) + 1151531653LL * SHIDWORD(timeout)) >> 32, | |
(unsigned __int64)(1151531653 * timeout) >> 32) | |
+ KHardwareTimer::GetSystemTick(&g_hardwareTimer); | |
v10 = HIDWORD(v11); | |
v9 = v11; | |
if ( ((((unsigned __int64)-__SPAIR64__(v10, v9) >> 32) & 0x80000000) != 0LL) == __OFSUB__(0, v10, v9 == 0) ) | |
{ | |
v9 = 0xFFFFFFFF; | |
v10 = 0x7FFFFFFF; | |
} | |
KSchedulerLock::Lock(&reused->lock); | |
} | |
else | |
{ | |
v9 = 0; | |
v10 = 0; | |
} | |
p_link = &this->waitList.link; | |
thread->arbitrationAddr = addr; | |
thread->synchronizationResult = 0x9401BFE; | |
thread->signaledObject = 0; | |
thread->waiterList = &this->waitList; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_PAUSED); | |
prev = this->waitList.link.prev; | |
if ( prev ) | |
v14 = &prev->link; | |
else | |
v14 = &this->waitList.link; | |
thread->link.prev = prev; | |
thread->link.next = 0; | |
v14->next = thread; | |
p_link->prev = thread; | |
if ( thread->shallTerminate ) | |
{ | |
link = thread->link; | |
if ( link.prev ) | |
v16 = &link.prev->link; | |
else | |
v16 = &this->waitList.link; | |
if ( link.next ) | |
p_link = &link.next->link; | |
v16->next = link.next; | |
p_link->prev = link.prev; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_RUNNING); | |
thread->waiterList = 0; | |
} | |
else | |
{ | |
if ( decrement ) | |
{ | |
CPSR = __get_CPSR(); | |
v18 = addr; | |
__disable_irq(); | |
v19 = CPSR; | |
__mcr(15, 0, v18 >> 12 << 12, 7, 8, 3); | |
v20 = __mrc(15, 0, 7, 4, 0); | |
if ( (v20 & 1) != 0 || !((v20 >> 12 << 12) | addr & 0xFFF) ) | |
{ | |
__set_CPSR(CPSR); | |
validAddr = 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
v22 = (KHardwareTimer *)__ldrex((unsigned int *)addr); | |
if ( (int)v22 >= value ) | |
break; | |
if ( !__strex((unsigned int)&v22[-1].lock.lockCount + 3, (unsigned int *)addr) ) | |
goto LABEL_24; | |
} | |
__clrex(); | |
LABEL_24: | |
reused = v22; | |
__set_CPSR(v19); | |
validAddr = 1; | |
} | |
} | |
else | |
{ | |
validAddr = CopyWordFromUser(&reused, (const void *)addr); | |
} | |
if ( validAddr ) | |
{ | |
if ( (int)reused < value ) | |
{ | |
if ( !timeout ) | |
{ | |
if ( ((((unsigned __int64)-__SPAIR64__(v10, v9) >> 32) & 0x80000000) != 0LL) != __OFSUB__(0, v10, v9 == 0) ) | |
{ | |
KSchedulerLock::UnlockSingleCoreResched(&g_hardwareTimer.lock); | |
v9 = 0; | |
v10 = 0; | |
} | |
v26 = thread->link; | |
v27 = &this->waitList.link; | |
if ( v26.prev ) | |
v28 = &v26.prev->link; | |
else | |
v28 = &this->waitList.link; | |
if ( v26.next ) | |
v27 = &v26.next->link; | |
v28->next = v26.next; | |
v27->prev = v26.prev; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_RUNNING); | |
v8 = 0x9401BFE; | |
thread->waiterList = 0; | |
} | |
} | |
else | |
{ | |
if ( ((((unsigned __int64)-__SPAIR64__(v10, v9) >> 32) & 0x80000000) != 0LL) != __OFSUB__(0, v10, v9 == 0) ) | |
{ | |
KSchedulerLock::UnlockSingleCoreResched(&g_hardwareTimer.lock); | |
v9 = 0; | |
v10 = 0; | |
} | |
v23 = thread->link; | |
v24 = &this->waitList.link; | |
if ( v23.prev ) | |
v25 = &v23.prev->link; | |
else | |
v25 = &this->waitList.link; | |
if ( v23.next ) | |
v24 = &v23.next->link; | |
v25->next = v23.next; | |
v24->prev = v23.prev; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_RUNNING); | |
thread->waiterList = 0; | |
} | |
} | |
else | |
{ | |
if ( ((((unsigned __int64)-__SPAIR64__(v10, v9) >> 32) & 0x80000000) != 0LL) != __OFSUB__(0, v10, v9 == 0) ) | |
{ | |
KSchedulerLock::UnlockSingleCoreResched(&g_hardwareTimer.lock); | |
v9 = 0; | |
v10 = 0; | |
} | |
v29 = thread->link; | |
v30 = &this->waitList.link; | |
if ( v29.prev ) | |
v31 = &v29.prev->link; | |
else | |
v31 = &this->waitList.link; | |
if ( v29.next ) | |
v30 = &v29.next->link; | |
v31->next = v29.next; | |
v30->prev = v29.prev; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_RUNNING); | |
v8 = -654305260; | |
thread->waiterList = 0; | |
} | |
} | |
if ( ((((unsigned __int64)-__SPAIR64__(v10, v9) >> 32) & 0x80000000) != 0LL) != __OFSUB__(0, v10, v9 == 0) ) | |
{ | |
if ( thread ) | |
v32 = &thread->KTimerTask; | |
else | |
v32 = 0; | |
KHardwareTimer::RegisterTask(&g_hardwareTimer, v32, __SPAIR64__(v10, v9)); | |
KSchedulerLock::UnlockSingleCoreResched(&g_hardwareTimer.lock); | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
if ( v8 >= 0 ) | |
{ | |
if ( ((((unsigned __int64)-timeout >> 32) & 0x80000000) != 0LL) != __OFSUB__( | |
0, | |
HIDWORD(timeout), | |
(_DWORD)timeout == 0) ) | |
{ | |
if ( thread ) | |
v33 = &thread->KTimerTask; | |
else | |
v33 = 0; | |
KHardwareTimer::CancelTask(&g_hardwareTimer, v33); | |
} | |
return thread->synchronizationResult; | |
} | |
return v8; | |
} | |
//----- (FFF0EE34) -------------------------------------------------------- | |
Result __fastcall KAddressArbiter::Signal(KAddressArbiter *value, u32 addr, s32 val) | |
{ | |
int numSignaled; // r7 | |
s32 v7; // r9 | |
KThread *v8; // r4 | |
KThread *v9; // r5 | |
int dynamicPriority; // r0 | |
KThreadIntrusiveLink *v11; // r1 | |
KThread *v12; // r0 | |
KThread *v13; // r2 | |
KThreadIntrusiveLink *v14; // r3 | |
KThread *next; // r4 | |
KThread *v16; // r5 | |
KThread *prev; // r1 | |
KThreadIntrusiveLink *p_link; // r2 | |
KThreadIntrusiveLink *v19; // r3 | |
numSignaled = 0; | |
if ( val < 0 ) // signal all | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
next = value->waitList.link.next; | |
if ( next ) | |
{ | |
do | |
{ | |
v16 = next->link.next; | |
if ( next->arbitrationAddr == addr ) | |
{ | |
next->signaledObject = 0; | |
next->synchronizationResult = 0; | |
prev = next->link.prev; | |
p_link = &value->waitList.link; | |
if ( prev ) | |
v19 = &prev->link; | |
else | |
v19 = &value->waitList.link; | |
if ( v16 ) | |
p_link = &v16->link; | |
v19->next = v16; | |
p_link->prev = prev; | |
KThread::SetSchedulingState(next, KTHREADSCHEDSTAT_RUNNING); | |
++numSignaled; | |
next->waiterList = 0; | |
} | |
next = v16; | |
} | |
while ( v16 ); | |
LABEL_25: | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
if ( numSignaled ) | |
return 0; | |
goto LABEL_28; | |
} | |
} | |
else | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
v7 = 0; | |
if ( val > 0 ) | |
{ | |
do | |
{ | |
v8 = value->waitList.link.next; | |
v9 = 0; | |
dynamicPriority = 0x80; | |
if ( !v8 ) | |
break; | |
do | |
{ | |
if ( v8->arbitrationAddr == addr && v8->dynamicPriority < dynamicPriority ) | |
{ | |
v9 = v8; | |
dynamicPriority = v8->dynamicPriority; | |
} | |
v8 = v8->link.next; | |
} | |
while ( v8 ); | |
if ( !v9 ) | |
break; | |
v9->signaledObject = 0; | |
v9->synchronizationResult = 0; | |
v11 = &value->waitList.link; | |
v12 = v9->link.prev; | |
v13 = v9->link.next; | |
if ( v12 ) | |
v14 = &v12->link; | |
else | |
v14 = &value->waitList.link; | |
if ( v13 ) | |
v11 = &v13->link; | |
v14->next = v13; | |
v11->prev = v12; | |
KThread::SetSchedulingState(v9, KTHREADSCHEDSTAT_RUNNING); | |
++v7; | |
++numSignaled; | |
v9->waiterList = 0; | |
} | |
while ( v7 < val ); | |
goto LABEL_25; | |
} | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
LABEL_28: | |
if ( (__mrc(15, 0, 0, 0, 5) & 3) == 0 && current.clc.current.thread->dynamicPriority >= 50 ) | |
cpu::WaitCycles(1614u); // Zelda games workaround (fasthax fix caused lag issues) | |
// This path is only called if numSignaled = 0 | |
return 0; // remove mch2 oracle | |
} | |
//----- (FFF0EFCC) -------------------------------------------------------- | |
Result __fastcall KInterruptEvent::ReenableInterrupt(KInterruptEvent *this) | |
{ | |
return KInterruptManager::ReenablePublicInterruptOrFiq(&g_interruptManager, this->irqId); | |
} | |
//----- (FFF0EFDC) -------------------------------------------------------- | |
void __fastcall KInterruptTaskManager::EnqueueTask(KInterruptTaskManager *this, KInterruptTask *task) | |
{ | |
KInterruptTask *last; // r2 | |
KScheduler *volatile scheduler; // r0 | |
last = this->last; | |
if ( last ) | |
last->next = task; | |
this->last = task; | |
if ( !last ) | |
this->first = task; | |
scheduler = current.clc.current.scheduler; | |
current.clc.current.scheduler->interruptTaskAdded = 1; | |
scheduler->reschedule = 1; | |
} | |
//----- (FFF0F00C) -------------------------------------------------------- | |
Result __fastcall KThread::InitializeUserThread( | |
KThread *this, | |
u32 ep, | |
u32 arg, | |
u32 stackTop, | |
s32 priority, | |
s32 idealCore, | |
KProcess *parentProcess) | |
{ | |
unsigned int *p_kernAllocatedForProcess; // r12 | |
u32 v13; // r3 | |
unsigned int v14; // r1 | |
u32 outAddr[10]; // [sp+18h] [bp-28h] BYREF | |
if ( KPageTable::OperateOnAnyFreeBlockInRegionWithGuardPage(// allocate kernel stack | |
&g_supervisorPageTable, | |
outAddr, | |
1u, | |
0xFF400000, | |
0x800u, | |
0, | |
KMEMSTATE_LOCKED, | |
KMEMPERM_KRW, | |
KMEMUPDATE_NONE, | |
MEMOP_REGION_BASE) < 0 ) | |
return 0xC8601801; | |
p_kernAllocatedForProcess = &parentProcess->kernAllocatedForProcess; | |
v13 = outAddr[0] + 0x1000; | |
do | |
v14 = __ldrex(p_kernAllocatedForProcess); | |
while ( __strex(v14 + 0x1000, p_kernAllocatedForProcess) ); | |
return KThread::Initialize(this, ep, arg, v13, stackTop, priority, idealCore, parentProcess, KTHREAD_TYPE_USER); | |
} | |
//----- (FFF0F0D4) -------------------------------------------------------- | |
void __fastcall KThreadContext::Initialize( | |
KThreadContext *this, | |
u32 ep, | |
u32 kernStackTop, | |
u32 stackTop, | |
u32 arg, | |
BOOL isUser) | |
{ | |
u32 v6; // r5 | |
u32 v7; // r8 | |
u32 v9; // r1 | |
u32 v10; // r5 | |
void (__fastcall __noreturn *v11)(int, int, int, int, int); // r12 | |
u32 v12; // r7 | |
u32 v13; // r2 | |
int v14; // r3 | |
u32 v15; // r1 | |
u32 *v17; // r5 | |
if ( kernStackTop ) | |
{ | |
v6 = kernStackTop & ~7u; | |
if ( isUser ) | |
{ | |
v7 = ep & 1; | |
if ( (ep & 1) != 0 ) | |
v7 = 32; | |
v9 = v6 - 16; | |
*(_DWORD *)(v6 - 4) = v7 | 0x10; | |
v10 = v6 - 4; | |
v11 = KThread::UserThreadStarter; | |
v12 = stackTop & ~7u; | |
*(_DWORD *)(v10 - 8) = 0; | |
*(_DWORD *)(v10 - 4) = ep; | |
v13 = v9; | |
v14 = 6; | |
*(_DWORD *)(v10 - 12) = v12; | |
do | |
{ | |
*(_DWORD *)(v13 - 4) = 0; | |
--v14; | |
*(_DWORD *)(v13 - 8) = 0; | |
v13 -= 8; | |
} | |
while ( v14 ); | |
*(_DWORD *)(v9 - 52) = arg; | |
v15 = v9 - 52; | |
} | |
else if ( ep ) | |
{ | |
v17 = (u32 *)(v6 - 4); | |
v15 = (u32)(v17 - 1); | |
v11 = (void (__fastcall __noreturn *)(int, int, int, int, int))KThread::SupervisorThreadStarter; | |
*v17 = ep; | |
*(v17 - 1) = arg; | |
} | |
else | |
{ | |
v11 = 0; | |
v15 = kernStackTop & ~7u; | |
} | |
this->r4 = 0; | |
this->r5 = 0; | |
this->r6 = 0; | |
this->r7 = 0; | |
this->r8 = 0; | |
this->r9 = 0; | |
this->r10 = 0; | |
this->r11 = 0; | |
this->sp = v15; | |
this->lr = (u32)v11; | |
this->fpscr = 0x3C00000; | |
this->fpexc = 0; | |
memset(this->d, 0, sizeof(this->d)); | |
} | |
} | |
// FFF13E44: using guessed type int KThread::SupervisorThreadStarter(); | |
//----- (FFF0F1BC) -------------------------------------------------------- | |
Result __fastcall KProcess::GetQtmStaticMappedSize(s32 *out, KProcess *this) | |
{ | |
u32 foundAddr; // r5 | |
u32 v5; // r3 | |
KProcessPageTable *p_pgTable; // r4 | |
Result result; // r0 | |
u32 v8; // r4 | |
KProcessPageTable *v9; // r8 | |
KMemoryInfo info2; // [sp+8h] [bp-40h] BYREF | |
KMemoryInfo outMemoryInfo; // [sp+18h] [bp-30h] BYREF | |
u32 v12; // [sp+28h] [bp-20h] BYREF | |
u32 pageInfo; // [sp+2Ch] [bp-1Ch] BYREF | |
v5 = 0x1E800000; | |
p_pgTable = &this->pgTable; | |
do | |
{ | |
if ( KPageTable::QueryInfo(p_pgTable, &outMemoryInfo, &pageInfo, v5) < 0 ) | |
break; | |
if ( outMemoryInfo.state == KMEMSTATE_STATIC ) | |
{ | |
foundAddr = outMemoryInfo.baseAddress; | |
result = 0; | |
goto LABEL_7; | |
} | |
v5 = outMemoryInfo.baseAddress + outMemoryInfo.size; | |
} | |
while ( outMemoryInfo.baseAddress + outMemoryInfo.size < 0x1EC00000 ); | |
result = -522183692; | |
LABEL_7: | |
if ( result >= 0 ) | |
{ | |
v8 = foundAddr; | |
v9 = &this->pgTable; | |
if ( foundAddr < 0x1EC00000 ) | |
{ | |
do | |
{ | |
if ( KPageTable::QueryInfo(v9, &info2, &v12, v8) < 0 ) | |
break; | |
if ( info2.state != KMEMSTATE_STATIC ) | |
break; | |
v8 = info2.baseAddress + info2.size; | |
} | |
while ( info2.baseAddress + info2.size < 0x1EC00000 ); | |
} | |
*out = v8 - foundAddr; | |
return 0; | |
} | |
return result; | |
} | |
// FFF0F22C: variable 'foundAddr' is possibly undefined | |
//----- (FFF0F290) -------------------------------------------------------- | |
Result __fastcall KProcess::GetQtmStaticMappedBase(s32 *out, KProcess *this) | |
{ | |
u32 v3; // r3 | |
KProcessPageTable *p_pgTable; // r5 | |
u32 pageInfo; // [sp+4h] [bp-24h] BYREF | |
KMemoryInfo outMemoryInfo; // [sp+8h] [bp-20h] BYREF | |
v3 = 511705088; | |
p_pgTable = &this->pgTable; | |
do | |
{ | |
if ( KPageTable::QueryInfo(p_pgTable, &outMemoryInfo, &pageInfo, v3) < 0 ) | |
break; | |
if ( outMemoryInfo.state == KMEMSTATE_STATIC ) | |
{ | |
*out = outMemoryInfo.baseAddress; | |
return 0; | |
} | |
v3 = outMemoryInfo.baseAddress + outMemoryInfo.size; | |
} | |
while ( outMemoryInfo.baseAddress + outMemoryInfo.size < 0x1EC00000 ); | |
return 0xE0E01BF4; | |
} | |
//----- (FFF0F308) -------------------------------------------------------- | |
BOOL __fastcall KProcess::ShouldOnlyUseSmallPages(u64 titleId) | |
{ | |
return titleId && titleId == g_systemControl.titleIdForSmallPageWorkaround; | |
} | |
//----- (FFF0F338) -------------------------------------------------------- | |
Result __fastcall KProcess::GetQtmStaticMappedConversionOffset(s32 *out, KProcess *this) | |
{ | |
u32 v3; // r3 | |
KProcessPageTable *p_pgTable; // r5 | |
Result result; // r0 | |
u32 pageInfo; // [sp+4h] [bp-24h] BYREF | |
KMemoryInfo outMemoryInfo; // [sp+8h] [bp-20h] BYREF | |
v3 = 0x1E800000; | |
p_pgTable = &this->pgTable; | |
do | |
{ | |
if ( KPageTable::QueryInfo(p_pgTable, &outMemoryInfo, &pageInfo, v3) < 0 ) | |
break; | |
if ( outMemoryInfo.state == KMEMSTATE_STATIC ) | |
{ | |
result = 0; | |
goto LABEL_7; | |
} | |
v3 = outMemoryInfo.baseAddress + outMemoryInfo.size; | |
} | |
while ( outMemoryInfo.baseAddress + outMemoryInfo.size < 0x1EC00000 ); | |
result = 0xE0E01BF4; | |
LABEL_7: | |
if ( result >= 0 ) | |
{ | |
*out = 0x800000; | |
return 0; | |
} | |
return result; | |
} | |
//----- (FFF0F3B8) -------------------------------------------------------- | |
u32 __fastcall KMemoryManager::ConvertSharedMemPaLinearWithAppMemType(u32 pa) | |
{ | |
u32 v1; // r0 | |
int v2; // r1 | |
v1 = pa - 0x20000000; | |
if ( (unsigned __int8)g_kernelSharedConfigPagePtr->appMemType == 7 ) | |
v2 = 0x30000000; | |
else | |
v2 = 0x14000000; // always use the old mapping... is that a bug? | |
return v1 + v2; | |
} | |
// FFF2F0D4: using guessed type KernelSharedConfig *g_kernelSharedConfigPagePtr; | |
//----- (FFF0F3E4) -------------------------------------------------------- | |
Result __fastcall StartInterProcessDma( | |
Handle *outDmaHandle, | |
Handle dstProcessHandle, | |
u32 dstAddr, | |
Handle srcProcessHandle, | |
u32 srcAddr, | |
u32 size, | |
const DmaConfig *config) | |
{ | |
bool v7; // zf | |
Result result; // r0 | |
u32 minSize; // r2 | |
Result v12; // r3 | |
int v13; // r9 | |
u32 adjSizeDst; // r1 | |
bool v15; // zf | |
Result v16; // r12 | |
u32 endAddrDst; // r1 | |
Result v18; // r1 | |
u32 adjSizeSrc; // r1 | |
bool v20; // zf | |
u32 endAddrSrc; // r1 | |
KHandleTable *p_handleTable; // r9 | |
KProcess *dstProcess; // r7 | |
KAutoObject *v24; // r0 | |
KAutoObject *v25; // r7 | |
u8 typeId; // r11 | |
int v27; // r1 | |
KProcess *v28; // r8 | |
KProcess *srcProcess; // r8 | |
KAutoObject *v30; // r0 | |
KAutoObject *v31; // r8 | |
u8 v32; // r10 | |
int v33; // r1 | |
KProcess *v34; // r9 | |
int v35; // r9 | |
KTypeObj v36; // [sp+0h] [bp-68h] BYREF | |
KDmaChannel *outDmaChannel; // [sp+Ch] [bp-5Ch] BYREF | |
DmaConfig dmaCfg; // [sp+10h] [bp-58h] BYREF | |
KTypeObj v39; // [sp+28h] [bp-40h] BYREF | |
v7 = dstAddr == 0; | |
*outDmaHandle = 0; | |
result = 0xD8E007F6; | |
if ( dstAddr ) | |
v7 = srcAddr == 0; | |
if ( !v7 ) | |
{ | |
v7 = !CopyBytesFromUser(&dmaCfg, config, 0x18u); | |
result = 0xE0E01BF5; | |
if ( v7 ) | |
v12 = 0xE0E01BF5; | |
else | |
v12 = 0; | |
if ( v12 < 0 ) | |
return v12; | |
v13 = 0xD8E007ED; | |
adjSizeDst = size; | |
if ( !((unsigned __int8)(dmaCfg.flags & DMACFGFLAG_DST_IS_DEVICE) >> 1) ) | |
goto LABEL_23; | |
if ( dmaCfg.dstCfg.allowedAlignments == 4 ) | |
{ | |
minSize = 4; | |
} | |
else | |
{ | |
v15 = dmaCfg.dstCfg.allowedAlignments == 8; | |
if ( dmaCfg.dstCfg.allowedAlignments != 8 ) | |
v15 = dmaCfg.dstCfg.allowedAlignments == 0xC; | |
if ( !v15 && dmaCfg.dstCfg.allowedAlignments != 0xF ) | |
{ | |
v16 = 0xD8E007ED; | |
LABEL_19: | |
if ( v16 < 0 ) | |
return v16; | |
if ( minSize < size ) | |
adjSizeDst = minSize; | |
LABEL_23: | |
if ( adjSizeDst ) | |
{ | |
endAddrDst = adjSizeDst + dstAddr - 1; | |
if ( dstAddr <= endAddrDst && endAddrDst < 0x40000000 ) | |
goto LABEL_26; | |
} | |
else if ( dstAddr < 0x40000000 ) | |
{ | |
LABEL_26: | |
v18 = 0; | |
goto LABEL_29; | |
} | |
v18 = 0xE0E01BF5; | |
LABEL_29: | |
if ( v18 < 0 ) | |
return v18; | |
adjSizeSrc = size; | |
if ( (dmaCfg.flags & DMACFGFLAG_SRC_IS_DEVICE) == 0 ) | |
goto LABEL_45; | |
if ( dmaCfg.srcCfg.allowedAlignments == 4 ) | |
{ | |
minSize = 4; | |
} | |
else | |
{ | |
v20 = dmaCfg.srcCfg.allowedAlignments == 8; | |
if ( dmaCfg.srcCfg.allowedAlignments != 8 ) | |
v20 = dmaCfg.srcCfg.allowedAlignments == 0xC; | |
if ( !v20 ) | |
v20 = dmaCfg.srcCfg.allowedAlignments == 0xF; | |
if ( !v20 ) | |
goto LABEL_42; | |
minSize = 8; | |
} | |
v13 = 0; | |
LABEL_42: | |
if ( v13 < 0 ) | |
return v13; | |
if ( minSize < size ) | |
adjSizeSrc = minSize; | |
LABEL_45: | |
if ( adjSizeSrc ) | |
{ | |
endAddrSrc = adjSizeSrc + srcAddr - 1; | |
if ( srcAddr <= endAddrSrc && endAddrSrc < 0x40000000 ) | |
goto LABEL_48; | |
} | |
else if ( srcAddr < 0x40000000 ) | |
{ | |
LABEL_48: | |
result = 0; | |
} | |
if ( result < 0 ) | |
return result; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
if ( dstProcessHandle == CUR_PROCESS_HANDLE ) | |
{ | |
dstProcess = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
} | |
else | |
{ | |
v24 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, dstProcessHandle); | |
v25 = v24; | |
if ( !v24 ) | |
return 0xD9001BF7; | |
v24->GetTypeObj(&v36, v24); | |
typeId = v36.typeId; | |
v25->GetTypeObj(&v39, v25); | |
v27 = typeId | 0xC5; | |
if ( v27 == v39.typeId ) | |
v28 = (KProcess *)v25; | |
else | |
v28 = 0; | |
if ( v27 != v39.typeId ) | |
v25->DecrementRefcount(v25); | |
dstProcess = v28; | |
} | |
if ( dstProcess ) | |
{ | |
if ( srcProcessHandle == CUR_PROCESS_HANDLE ) | |
{ | |
srcProcess = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
} | |
else | |
{ | |
v30 = KHandleTable::ConvertToAutoObject(p_handleTable, srcProcessHandle); | |
v31 = v30; | |
if ( !v30 ) | |
goto LABEL_76; | |
v30->GetTypeObj(&v36, v30); | |
v32 = v36.typeId; | |
v31->GetTypeObj(&v39, v31); | |
v33 = v32 | 0xC5; | |
if ( v33 == v39.typeId ) | |
v34 = (KProcess *)v31; | |
else | |
v34 = 0; | |
if ( v33 != v39.typeId ) | |
v31->DecrementRefcount(v31); | |
srcProcess = v34; | |
} | |
if ( srcProcess ) | |
{ | |
v35 = KDmaManager::ValidateUserParameters(dstAddr, srcAddr, size, &dmaCfg, dstProcess, srcProcess); | |
if ( v35 < 0 ) | |
{ | |
dstProcess->DecrementRefcount(dstProcess); | |
srcProcess->DecrementRefcount(srcProcess); | |
return v35; | |
} | |
v13 = KDmaManager::InitializeChannel( | |
&g_dmaManager, | |
outDmaHandle, | |
&outDmaChannel, | |
dmaCfg.channelId, | |
dmaCfg.flags); | |
if ( v13 >= 0 ) | |
{ | |
KDmaChannel::Start(outDmaChannel, dstAddr, srcAddr, size, &dmaCfg, dstProcess, srcProcess); | |
} | |
else | |
{ | |
dstProcess->DecrementRefcount(dstProcess); | |
srcProcess->DecrementRefcount(srcProcess); | |
} | |
return v13; | |
} | |
LABEL_76: | |
dstProcess->DecrementRefcount(dstProcess); | |
return 0xD9001BF7; | |
} | |
return 0xD9001BF7; | |
} | |
minSize = 8; | |
} | |
v16 = 0; | |
goto LABEL_19; | |
} | |
return result; | |
} | |
// FFF0F4A8: variable 'minSize' is possibly undefined | |
//----- (FFF0F7EC) -------------------------------------------------------- | |
void __fastcall WaitSynchronizationNImpl(WaitSynchronizationNArgs *args, KSynchronizationObject **objects) | |
{ | |
u32 zero; // r7 | |
s32 v5; // r6 | |
s32 v6; // r2 | |
KHandleTable *p_handleTable; // r9 | |
Result v8; // r0 | |
KAutoObject *v9; // r0 | |
KSynchronizationObject *v10; // r4 | |
u8 typeId; // r11 | |
int v12; // r1 | |
KSynchronizationObject *v13; // r10 | |
s32 numHandles; // r0 | |
int timeout_high; // r3 | |
s32 i; // r4 | |
u32 tmp; // [sp+4h] [bp-5Ch] BYREF | |
s64 v18; // [sp+8h] [bp-58h] | |
KSynchronization *v19; // [sp+18h] [bp-48h] | |
KTypeObj v20; // [sp+28h] [bp-38h] BYREF | |
KTypeObj v21; // [sp+30h] [bp-30h] BYREF | |
v5 = 0; | |
v6 = args->numHandles; | |
if ( v6 > 0 ) | |
zero = 0; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
v19 = &g_synchronization; | |
if ( v6 > 0 ) | |
{ | |
do | |
{ | |
tmp = zero; | |
v8 = CopyWordFromUser(&tmp, &args->handles[v5]) ? 0 : 0xE0E01BF5; | |
args->res = v8; | |
if ( v8 < 0 ) | |
break; | |
v9 = KHandleTable::ConvertToAutoObject(p_handleTable, tmp); | |
v10 = (KSynchronizationObject *)v9; | |
if ( !v9 ) | |
goto LABEL_21; | |
v9->GetTypeObj(&v21, v9); | |
typeId = v21.typeId; | |
v10->GetTypeObj(&v20, v10); | |
v12 = typeId | 1; | |
if ( v12 == v20.typeId ) | |
v13 = v10; | |
else | |
v13 = (KSynchronizationObject *)zero; | |
if ( v12 != v20.typeId ) | |
v10->DecrementRefcount(v10); | |
if ( !v13 ) | |
{ | |
LABEL_21: | |
args->res = 0xD8E007F7; | |
break; | |
} | |
objects[v5++] = v13; | |
} | |
while ( args->numHandles > v5 ); | |
} | |
numHandles = args->numHandles; | |
if ( numHandles == v5 ) | |
{ | |
timeout_high = HIDWORD(args->timeout); | |
LODWORD(v18) = args->timeout; | |
HIDWORD(v18) = timeout_high; | |
args->res = KSynchronization::WaitSynchronizationN( | |
v19, | |
args->outIdx, | |
current.clc.current.thread, | |
objects, | |
numHandles, | |
args->waitAll, | |
v18); | |
} | |
for ( i = 0; v5 > i; ++i ) // close all translated objects, esp. if one handle has failed translation | |
objects[i]->DecrementRefcount(objects[i]); | |
} | |
// FFF0F824: variable 'zero' is possibly undefined | |
//----- (FFF0F978) -------------------------------------------------------- | |
// local variable allocation has failed, the output may be wrong! | |
void __fastcall ReplyAndReceiveImpl(ReplyAndReceiveArgs *args, KSynchronizationObject **syncObjects) | |
{ | |
int numHandles; // r6 | |
Result v5; // r4 | |
Handle replyTargetHandle; // r2 | |
Handle *handles; // r10 | |
int v8; // r0 | |
int v9; // r1 | |
int v10; // r1 | |
int v11; // r9 | |
KSynchronizationObject *v12; // r8 | |
KAutoObject *v13; // r0 | |
int v14; // r1 | |
KSynchronizationObject *v15; // r5 | |
KAutoObject *v16; // r0 | |
KServerSession *v17; // r4 | |
unsigned __int8 v18; // r8 | |
int v19; // r1 | |
KServerSession *v20; // r5 | |
Result v21; // r8 | |
KServerSession *v22; // r5 | |
unsigned __int8 v23; // r9 | |
Result v24; // r0 | |
int v25; // r4 | |
KSynchronizationObject *v26; // r0 | |
u32 reused_stackloc; // [sp+8h] [bp-78h] BYREF | |
Handle replyTargetHandle_reused; // [sp+Ch] [bp-74h] | |
KThread *thread; // [sp+14h] [bp-6Ch] | |
s32 *v30; // [sp+20h] [bp-60h] | |
s32 outIdx; // [sp+28h] [bp-58h] BYREF | |
int v32; // [sp+2Ch] [bp-54h] | |
KTypeObj v33; // [sp+38h] [bp-48h] BYREF | |
KTypeObj v34; // [sp+40h] [bp-40h] BYREF | |
KHandleTable *p_handleTable; // [sp+48h] [bp-38h] | |
unsigned int v36; // [sp+4Ch] [bp-34h] | |
int v37; // [sp+54h] [bp-2Ch] | |
numHandles = args->numHandles; | |
v5 = -404488193; | |
v30 = args->outIdx; | |
replyTargetHandle = args->replyTargetHandle; | |
handles = args->handles; | |
if ( numHandles > 0 ) | |
{ | |
v8 = numHandles & 1; | |
v9 = 0; | |
if ( v8 == 1 ) | |
{ | |
v9 = 1; | |
*syncObjects = 0; | |
} | |
for ( ; v8 < numHandles; v9 = v10 + 1 ) | |
{ | |
syncObjects[v9] = 0; | |
v10 = v9 + 1; | |
v8 += 2; | |
syncObjects[v10] = 0; | |
} | |
} | |
replyTargetHandle_reused = replyTargetHandle; | |
v11 = 0; | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
thread = current.clc.current.thread; | |
if ( numHandles <= 0 ) | |
{ | |
all_translated: | |
if ( HIWORD(*(_DWORD *)(__mrc(15, 0, 13, 0, 3) + 128)) != 0xFFFF && replyTargetHandle_reused ) | |
{ // reply part | |
v16 = KHandleTable::ConvertToAutoObject(p_handleTable, replyTargetHandle_reused); | |
v17 = (KServerSession *)v16; | |
if ( !v16 ) | |
goto LABEL_28; | |
v16->GetTypeObj((KTypeObj *)&outIdx, v16); | |
v18 = v32; | |
v17->GetTypeObj((KTypeObj *)&reused_stackloc, v17); | |
v19 = v18 | 0x95; | |
if ( v19 == (unsigned __int8)replyTargetHandle_reused ) | |
v20 = v17; | |
else | |
v20 = 0; | |
if ( v19 != (unsigned __int8)replyTargetHandle_reused ) | |
v17->DecrementRefcount(v17); | |
if ( !v20 ) | |
{ | |
LABEL_28: | |
v21 = 0xD8E007F7; | |
goto LABEL_41; | |
} | |
v5 = KServerSession::ReplyOrAbortRequest(v20, thread, 1); | |
if ( v5 < 0 ) | |
{ | |
v21 = v5; | |
*v30 = -1; | |
v20->DecrementRefcount(v20); | |
goto LABEL_41; | |
} | |
v20->DecrementRefcount(v20); | |
} | |
if ( numHandles > 0 ) | |
{ | |
do | |
{ | |
v5 = KSynchronization::WaitSynchronizationN( | |
&g_synchronization, | |
&outIdx, | |
thread, | |
syncObjects, | |
numHandles, | |
0, | |
-1LL); | |
if ( v5 < 0 ) | |
break; | |
v22 = (KServerSession *)syncObjects[outIdx]; | |
v22->GetTypeObj((KTypeObj *)&reused_stackloc, v22); | |
v23 = replyTargetHandle_reused; | |
v22->GetTypeObj(&v33, v22); | |
if ( (v23 | 0x95) != v33.typeId ) | |
break; | |
v24 = KServerSession::ReceiveSyncRequest(v22, thread); | |
v5 = v24; | |
} | |
while ( v24 == 0xC8A01836 ); // ignore request with too fragmented pxibufs | |
*v30 = outIdx; | |
} | |
else | |
{ | |
*v30 = 0; | |
} | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
v12 = 0; | |
reused_stackloc = 0; | |
v5 = CopyWordFromUser(&reused_stackloc, &handles[v11]) ? 0 : 0xE0E01BF5; | |
if ( v5 < 0 ) | |
break; | |
v13 = KHandleTable::ConvertToAutoObject(p_handleTable, reused_stackloc); | |
v15 = (KSynchronizationObject *)v13; | |
if ( v13 ) | |
{ | |
v36 = v14 & 0xFFFFFF00 | 1; // any kind of sync object | |
v13->GetTypeObj(&v33, v13); | |
v37 = *(_DWORD *)&v33.typeId; | |
v15->GetTypeObj(&v34, v15); | |
if ( ((unsigned __int8)v36 | (unsigned __int8)v37) == v34.typeId ) | |
v12 = v15; | |
else | |
v15->DecrementRefcount(v15); | |
} | |
syncObjects[v11] = v12; | |
if ( !v12 ) | |
goto LABEL_28; | |
if ( numHandles <= ++v11 ) | |
goto all_translated; | |
} | |
} | |
v21 = v5; | |
LABEL_41: | |
v25 = 0; | |
if ( v21 == 0xD9400415 ) | |
v21 = 0xC920181A; | |
if ( numHandles > 0 ) | |
{ | |
do | |
{ | |
v26 = syncObjects[v25]; | |
if ( v26 ) | |
v26->DecrementRefcount(v26); | |
++v25; | |
} | |
while ( v25 < numHandles ); | |
} | |
args->res = v21; | |
} | |
// FFF0F978: variables would overlap: lvar "reused_stackloc" ^8.4(user-defined) and ^8.8 | |
//----- (FFF0FD1C) -------------------------------------------------------- | |
void __fastcall GetThreadListImpl(GetThreadListArgs *args, u32 *tidBuffer) | |
{ | |
Handle processHandle; // r1 | |
KProcess *v5; // r7 | |
KProcess *volatile process; // r5 | |
KProcess *v7; // r0 | |
KAutoObject *v8; // r0 | |
KAutoObject *v9; // r5 | |
u8 typeId; // r9 | |
int v11; // r0 | |
s32 v12; // r5 | |
unsigned int v13; // r2 | |
bool v14; // zf | |
KThreadLinkedListNode *node; // r0 | |
s32 i; // r5 | |
Result v17; // r0 | |
KTypeObj v18; // [sp+0h] [bp-30h] BYREF | |
KTypeObj v19; // [sp+8h] [bp-28h] BYREF | |
u32 src; // [sp+10h] [bp-20h] BYREF | |
processHandle = args->processHandle; | |
v5 = 0; | |
if ( !processHandle ) // if no process handle, dump all thread ids | |
{ | |
v12 = 0; | |
v13 = __ldrex((unsigned int *)&g_threadAllocator.container.mutex); | |
v14 = v13 == 0; | |
if ( v13 ) | |
__strex(v13, (unsigned int *)&g_threadAllocator.container.mutex); | |
else | |
v13 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_threadAllocator.container.mutex); | |
if ( v14 ) | |
v14 = v13 == 0; | |
if ( !v14 ) | |
KLightMutex::LockImpl(&g_threadAllocator.container.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
for ( node = (KThreadLinkedListNode *)g_threadAllocator.container.list.link.next; | |
node != (KThreadLinkedListNode *)&g_threadAllocator.container.list.link; | |
++v12 ) | |
{ | |
if ( args->maxNumThreads > v12 ) | |
tidBuffer[v12] = node->thread->threadId; | |
node = node->link.next; | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_threadAllocator.container.mutex.lockingThread = 0; | |
if ( g_threadAllocator.container.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_threadAllocator.container.mutex); | |
*args->outNumThreads = v12; | |
v11 = 0; | |
goto LABEL_27; | |
} | |
if ( processHandle == CUR_PROCESS_HANDLE ) | |
{ | |
process = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
v7 = process; | |
} | |
else | |
{ | |
v8 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, processHandle); | |
v9 = v8; | |
if ( !v8 ) | |
{ | |
LABEL_11: | |
args->result = 0xD8E007F7; | |
return; | |
} | |
v8->GetTypeObj(&v18, v8); | |
typeId = v18.typeId; | |
v9->GetTypeObj(&v19, v9); | |
if ( (typeId | 0xC5) == v19.typeId ) | |
v5 = (KProcess *)v9; | |
else | |
v9->DecrementRefcount(v9); | |
v7 = v5; | |
} | |
if ( !v7 ) | |
goto LABEL_11; | |
v11 = KProcess::DumpThreadIds(v7, args->outNumThreads, tidBuffer, args->maxNumThreads); | |
LABEL_27: | |
args->result = v11; // they forget to decref the process! | |
if ( v11 >= 0 ) | |
{ | |
for ( i = 0; args->maxNumThreads > i; ++i ) | |
{ | |
src = tidBuffer[i]; | |
if ( CopyWordToUser(&args->outThreadIds[i], &src) ) | |
v17 = 0; | |
else | |
v17 = 0xE0E01BF5; | |
args->result = v17; | |
if ( v17 < 0 ) | |
break; | |
} | |
} | |
} | |
//----- (FFF0FF30) -------------------------------------------------------- | |
void __fastcall GetProcessListImpl(GetProcessListArgs *args, u32 *pidBuffer) | |
{ | |
int res; // r0 | |
int v5; // r5 | |
Result v6; // r0 | |
u32 v7; // [sp+0h] [bp-18h] BYREF | |
res = KProcess::GetProcessList(args->outNumProcesses, pidBuffer, args->maxNumProcesses); | |
args->result = res; | |
if ( res >= 0 ) | |
{ | |
v5 = 0; | |
if ( args->maxNumProcesses <= 0 ) | |
{ | |
LABEL_8: | |
args->result = 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
v7 = pidBuffer[v5]; | |
v6 = CopyWordToUser(&args->outPids[v5], &v7) ? 0 : 0xE0E01BF5; | |
args->result = v6; | |
if ( v6 < 0 ) | |
break; | |
if ( args->maxNumProcesses <= ++v5 ) | |
goto LABEL_8; | |
} | |
} | |
} | |
} | |
//----- (FFF0FFB8) -------------------------------------------------------- | |
Result __fastcall KDmaChannel::Restart( | |
KDmaChannel *this, | |
u32 dstAddr, | |
u32 srcAddr, | |
u32 size, | |
DmaRestartFlags restartFlags) | |
{ | |
KLightMutex *p_mutex; // r0 | |
KLightMutex *v10; // r5 | |
unsigned int v11; // r2 | |
bool v12; // zf | |
unsigned int v13; // r3 | |
int state; // r0 | |
bool v15; // zf | |
bool v16; // zf | |
s32 v17; // r0 | |
s32 minOffset; // r11 | |
int v19; // r1 | |
u32 maxVa; // r2 | |
u32 currentVa; // r3 | |
bool v22; // zf | |
s32 v23; // r0 | |
s32 v24; // r11 | |
int v25; // r1 | |
u32 v26; // r2 | |
u32 v27; // r3 | |
bool v28; // zf | |
BOOL dontReuseProgram; // r11 | |
s32 v30; // r2 | |
u32 currentPa; // r1 | |
BOOL v32; // r0 | |
BOOL v33; // r0 | |
KDmaProgram *p_programStorage; // r0 | |
Result v35; // r4 | |
KLightMutex *v36; // r0 | |
u32 v37; // r2 | |
u32 v38; // r1 | |
BOOL v39; // r1 | |
s32 maxOffset; // [sp+0h] [bp-48h] | |
s32 maxOffseta; // [sp+0h] [bp-48h] | |
KDmaAddress v43; // [sp+4h] [bp-44h] BYREF | |
KDmaBufferSize v44; // [sp+18h] [bp-30h] BYREF | |
p_mutex = &this->mutex; | |
v10 = p_mutex; | |
v11 = __ldrex((unsigned int *)p_mutex); | |
v12 = v11 == 0; | |
if ( v11 ) | |
v13 = __strex(v11, (unsigned int *)p_mutex); | |
else | |
v13 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)p_mutex); | |
if ( !v11 ) | |
v12 = v13 == 0; | |
if ( !v12 ) | |
KLightMutex::LockImpl(p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
state = (unsigned __int8)this->state; | |
v15 = state == KDMACHANSTATE_STARTED; | |
if ( state != KDMACHANSTATE_STARTED ) | |
v15 = state == KDMACHANSTATE_RESTARTED; | |
if ( !v15 ) | |
v15 = !this->keepLocked; | |
if ( !v15 ) | |
{ | |
if ( size | srcAddr ) | |
{ | |
v16 = size == 0; | |
if ( size ) | |
v16 = this->dmaSize.size == size; | |
if ( v16 ) | |
{ | |
v17 = this->dmaSize.srcBufferSize.maxOffset; | |
minOffset = this->dmaSize.srcBufferSize.minOffset; | |
} | |
else | |
{ | |
memset(&v44, 0, sizeof(v44)); | |
KDmaBufferSize::ComputeFromConfig(&v44, size, &this->dmaConfig.dstCfg); | |
v17 = v44.maxOffset; | |
minOffset = v44.minOffset; | |
} | |
maxOffset = v17; | |
v19 = *(_DWORD *)&this->srcDmaAddress.isDevice; | |
maxVa = this->srcDmaAddress.maxVa; | |
currentVa = this->srcDmaAddress.currentVa; | |
v43.currentPa = this->srcDmaAddress.currentPa; | |
*(_DWORD *)&v43.isDevice = v19; | |
v43.maxVa = maxVa; | |
v43.currentVa = currentVa; | |
v43.process = this->srcDmaAddress.process; | |
KDmaAddress::ResetAddress(&v43, srcAddr); | |
if ( !KDmaAddress::CheckBufferRangeValid(&v43, minOffset, maxOffset) ) | |
{ | |
v35 = 0xE0E01BF5; | |
v36 = v10; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v10->lockingThread = 0; | |
if ( v10->numWaiters <= 0 ) | |
return v35; | |
goto LABEL_56; | |
} | |
if ( !KDmaAddress::CheckVirtualAddressBlockUsable(&v43, minOffset, maxOffset, 0) ) | |
{ | |
v35 = 0xD9000402; | |
v36 = v10; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v10->lockingThread = 0; | |
if ( v10->numWaiters <= 0 ) | |
return v35; | |
goto LABEL_56; | |
} | |
} | |
if ( size | dstAddr ) | |
{ | |
v22 = size == 0; | |
if ( !size ) | |
v22 = this->dmaSize.size == 0; | |
if ( v22 ) | |
{ | |
v23 = this->dmaSize.dstBufferSize.maxOffset; | |
v24 = this->dmaSize.dstBufferSize.minOffset; | |
} | |
else | |
{ | |
memset(&v44, 0, sizeof(v44)); | |
KDmaBufferSize::ComputeFromConfig(&v44, size, &this->dmaConfig.srcCfg); | |
v23 = v44.maxOffset; | |
v24 = v44.minOffset; | |
} | |
maxOffseta = v23; | |
v25 = *(_DWORD *)&this->dstDmaAddress.isDevice; | |
v26 = this->dstDmaAddress.maxVa; | |
v27 = this->dstDmaAddress.currentVa; | |
v43.currentPa = this->dstDmaAddress.currentPa; | |
*(_DWORD *)&v43.isDevice = v25; | |
v43.maxVa = v26; | |
v43.currentVa = v27; | |
v43.process = this->dstDmaAddress.process; | |
KDmaAddress::ResetAddress(&v43, dstAddr); | |
if ( !KDmaAddress::CheckBufferRangeValid(&v43, v24, maxOffseta) ) | |
{ | |
v35 = 0xE0E01BF5; | |
v36 = v10; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v10->lockingThread = 0; | |
if ( v10->numWaiters <= 0 ) | |
return v35; | |
goto LABEL_56; | |
} | |
if ( !KDmaAddress::CheckVirtualAddressBlockUsable(&v43, v24, maxOffseta, 1) ) | |
{ | |
v35 = 0xD9000402; | |
v36 = v10; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v10->lockingThread = 0; | |
if ( v10->numWaiters <= 0 ) | |
return v35; | |
goto LABEL_56; | |
} | |
} | |
if ( !size ) | |
size = this->dmaSize.size; | |
this->dmaObject->signaled = 0; | |
this->keepLocked = (restartFlags & 1) == 0; | |
v28 = !this->dmaConfig.dstIsContiguous; | |
if ( this->dmaConfig.dstIsContiguous ) | |
v28 = !this->dmaConfig.srcIsContiguous; | |
dontReuseProgram = v28 || this->needCodeRegen; | |
if ( !KDmaAddress::ResetAddress(&this->dstDmaAddress, dstAddr) ) | |
dontReuseProgram = 1; | |
v12 = !KDmaAddress::ResetAddress(&this->srcDmaAddress, srcAddr); | |
v30 = this->dmaSize.size; | |
currentPa = this->srcDmaAddress.currentPa; | |
if ( v12 ) | |
dontReuseProgram = 1; | |
this->dmaConfig.dstAddr = this->dstDmaAddress.currentPa; | |
this->dmaConfig.srcAddr = currentPa; | |
if ( v30 != size ) | |
{ | |
this->dmaSize.size = size; | |
KDmaBufferSize::ComputeFromConfig(&this->dmaSize.dstBufferSize, size, &this->dmaConfig.srcCfg); | |
KDmaBufferSize::ComputeFromConfig(&this->dmaSize.srcBufferSize, size, &this->dmaConfig.dstCfg); | |
dontReuseProgram = 1; | |
} | |
if ( dstAddr ) | |
{ | |
v32 = KDmaAddress::CheckPhysicalMemContiguous( | |
&this->dstDmaAddress, | |
this->dmaSize.dstBufferSize.minOffset, | |
this->dmaSize.dstBufferSize.maxOffset); | |
if ( !v32 ) | |
dontReuseProgram = 1; | |
this->dmaConfig.dstIsContiguous = v32; | |
} | |
if ( srcAddr ) | |
{ | |
v33 = KDmaAddress::CheckPhysicalMemContiguous( | |
&this->srcDmaAddress, | |
this->dmaSize.srcBufferSize.minOffset, | |
this->dmaSize.srcBufferSize.maxOffset); | |
if ( !v33 ) | |
dontReuseProgram = 1; | |
this->dmaConfig.srcIsContiguous = v33; | |
if ( !v33 ) | |
goto LABEL_87; | |
} | |
if ( dontReuseProgram ) | |
{ | |
LABEL_87: | |
p_programStorage = &this->programStorage; | |
if ( this != (KDmaChannel *)-232 ) | |
p_programStorage = KDmaProgram::KDmaProgram(p_programStorage); | |
this->program = p_programStorage; | |
p_programStorage->Configure(p_programStorage, &this->dmaConfig, 0, KDMABLOCKTYPE_BODY); | |
if ( dontReuseProgram ) | |
{ | |
this->transferredDmaSize.size = 0; | |
KDmaBufferSize::operator=(&this->transferredDmaSize.dstBufferSize, 0); | |
KDmaBufferSize::operator=(&this->transferredDmaSize.srcBufferSize, 0); | |
this->needCodeRegen = 0; | |
KDmaChannel::BuildProgramAndRun(this, (((unsigned int)restartFlags >> 1) & 1) == 0);// DMARSTFLAG_DONT_FLUSH_PERIPHERAL | |
goto LABEL_83; | |
} | |
} | |
do | |
{ | |
if ( KDmaController::IsManagerFaulting() || KDmaController::IsChannelFaulting(this->channelId) ) | |
kernelpanic(); | |
} | |
while ( KDmaController::GetChannelStatus(this->channelId) ); | |
if ( srcAddr ) | |
v37 = this->dmaConfig.srcAddr; | |
else | |
v37 = 0; | |
if ( dstAddr ) | |
v38 = this->dmaConfig.dstAddr; | |
else | |
v38 = 0; | |
KDmaInstructionFactory::MutateMovDarMovSarInsts(&this->instFactory, v38, v37); | |
if ( (((unsigned int)restartFlags >> 1) & 1) != 0 )// DMARSTFLAG_DONT_FLUSH_PERIPHERAL | |
{ | |
KDmaInstructionFactory::ReplaceFlushPByNop(&this->instFactory); | |
} | |
else if ( this->dmaConfig.dstIsDevice || this->dmaConfig.srcIsDevice ) | |
{ | |
v39 = 1; | |
LABEL_82: | |
KDmaChannel::StartExecutingCode(this, v39); | |
LABEL_83: | |
v35 = 0; | |
v36 = v10; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v10->lockingThread = 0; | |
if ( v10->numWaiters <= 0 ) | |
return v35; | |
goto LABEL_56; | |
} | |
v39 = 0; | |
goto LABEL_82; | |
} | |
v35 = 0xD8E007E8; | |
v36 = v10; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v10->lockingThread = 0; | |
if ( v10->numWaiters > 0 ) | |
LABEL_56: | |
KLightMutex::UnlockImpl(v36); | |
return v35; | |
} | |
//----- (FFF10478) -------------------------------------------------------- | |
KPort *__fastcall KPort::KPort(KPort *this) | |
{ | |
KPort *v1; // r0 | |
KServerPort *__shifted(KPort,8) v2; // r0 | |
KServerPort *__shifted(KPort,0x2C) v3; // r0 | |
v1 = (KPort *)KAutoObject::KAutoObject(this); | |
v1->__vftable = &KPort::vt; | |
v2 = (KServerPort *__shifted(KPort,8))KSynchronizationObject::KSynchronizationObject(&v1->server); | |
ADJ(v2)->server.__vftable = &KServerPort::vt; | |
ADJ(v2)->server.incomingServerSessions.link.next = (KServerSessionLinkedListNode *)&ADJ(v2)->server.incomingServerSessions.link; | |
ADJ(v2)->server.incomingServerSessions.count = 0; | |
ADJ(v2)->server.incomingServerSessions.link.prev = (KServerSessionLinkedListNode *)&ADJ(v2)->server.incomingServerSessions.link; | |
v3 = (KServerPort *__shifted(KPort,0x2C))KSynchronizationObject::KSynchronizationObject(&ADJ(v2)->client); | |
ADJ(v3)->client.__vftable = &KClientPort::vt; | |
ADJ(v3)->client.currentSessionCount = 0; | |
return ADJ(v3); | |
} | |
//----- (FFF104D4) -------------------------------------------------------- | |
void __fastcall KEvent::Initialize(KEvent *this, KProcess *ownerProcess, ResetType resetType) | |
{ | |
u8 v4; // r4 | |
v4 = resetType; | |
KAutoObject::IncrementRefcount(ownerProcess); | |
this->ownerProcess = ownerProcess; | |
this->signaled = 0; | |
this->manualInterruptReenable = 0; | |
this->resetType = v4; | |
} | |
//----- (FFF10504) -------------------------------------------------------- | |
Result __fastcall KMutex::Initialize(KMutex *this, KProcess *owner, BOOL initiallyLocked) | |
{ | |
Result result; // r0 | |
KAutoObject::IncrementRefcount(owner); | |
this->ownerProcess = owner; | |
if ( initiallyLocked ) | |
{ | |
this->lockCount = 1; | |
this->lockingThread = current.clc.current.thread; | |
KThread::AcquireMutex(current.clc.current.thread, this); | |
} | |
else | |
{ | |
this->lockCount = 0; | |
this->lockingThread = 0; | |
} | |
result = 63; | |
this->priority = 63; | |
return result; | |
} | |
//----- (FFF10568) -------------------------------------------------------- | |
void __fastcall KMutex::ForceUnlock(KMutex *this, KThread *thread) | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( this->lockCount > 0 ) | |
{ | |
this->lockCount = 0; | |
this->lockingThread = 0; | |
KThread::RelinquishMutex(thread, this); | |
KSynchronizationObject::NotifyWaiters(this, 0); | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
//----- (FFF105BC) -------------------------------------------------------- | |
void __fastcall KTimer::Initialize(KTimer *this, KProcess *ownerProcess, ResetType resetType) | |
{ | |
u8 v4; // r4 | |
v4 = resetType; | |
KAutoObject::IncrementRefcount(ownerProcess); | |
this->ownerProcess = ownerProcess; | |
this->signaled = 0; | |
this->resetType = v4; | |
this->allowedToRegister = 0; | |
} | |
//----- (FFF105EC) -------------------------------------------------------- | |
Result __fastcall KTimer::Set(KTimer *this, s64 initialTimeoutNs, s64 intervalNs) | |
{ | |
__int64 v3; // r4 | |
s64 SystemTick; // r0 | |
signed __int64 currentTimeNs; // r6 | |
unsigned int v8; // r12 | |
unsigned int v9; // r1 | |
BOOL v11; // [sp+Ch] [bp-94h] | |
__int64 thread; // [sp+28h] [bp-78h] | |
int v13; // [sp+44h] [bp-5Ch] | |
SystemTick = KHardwareTimer::GetSystemTick(&g_hardwareTimer); | |
currentTimeNs = 0xBAD34AEELL * SHIDWORD(SystemTick) | |
+ 3LL * (unsigned int)SystemTick | |
+ __PAIR64__(3 * HIDWORD(SystemTick), (0xBAD34AEE * (unsigned __int64)(unsigned int)SystemTick) >> 32); | |
thread = (unsigned int)current.clc.current.thread; | |
v8 = __ldrex((unsigned int *)&g_timerOpsMutex); | |
v9 = 1; | |
if ( v8 == HIDWORD(thread) ) | |
v9 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_timerOpsMutex); | |
else | |
__strex(v8, (unsigned int *)&g_timerOpsMutex); | |
if ( v9 ) | |
KLightMutex::LockImpl(&g_timerOpsMutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
this->intervalLo = intervalNs; | |
this->intervalHi = HIDWORD(intervalNs); | |
if ( ((((unsigned __int64)-initialTimeoutNs >> 32) & 0x80000000) != 0LL) != __OFSUB__( | |
0, | |
HIDWORD(initialTimeoutNs), | |
(_DWORD)initialTimeoutNs == 0) ) | |
{ | |
v3 = currentTimeNs + initialTimeoutNs; | |
if ( currentTimeNs + initialTimeoutNs < currentTimeNs )// clamp to INT64_MAX | |
v3 = 0x7FFFFFFFFFFFFFFFLL; | |
this->nextTimeLo = v3; | |
this->nextTimeHi = HIDWORD(v3); | |
this->signaled = 0; | |
this->allowedToRegister = 1; | |
v13 = 1; | |
} | |
else | |
{ | |
this->nextTimeLo = currentTimeNs; // clamp to 0 | |
this->nextTimeHi = HIDWORD(currentTimeNs); | |
v13 = 0; | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_timerOpsMutex.lockingThread = 0; | |
if ( g_timerOpsMutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_timerOpsMutex); | |
if ( v13 ) | |
{ | |
KHardwareTimer::Sanitize(&g_hardwareTimer); | |
KSchedulerLock::Lock(&g_hardwareTimer.lock); | |
v11 = KHardwareTimer::RegisterTask( | |
&g_hardwareTimer, | |
&this->KTimerTask, | |
__SPAIR64__( | |
(0x44A2FA85LL * SHIDWORD(v3) + ((0x44A2FA85 * (unsigned __int64)(unsigned int)v3) >> 32)) >> 32, | |
(unsigned __int64)(0x44A2FA85 * v3) >> 32)); | |
KSchedulerLock::UnlockSingleCoreResched(&g_hardwareTimer.lock); | |
if ( !v11 ) | |
KAutoObject::IncrementRefcount(this); | |
} | |
else | |
{ | |
this->allowedToRegister = 0; | |
if ( KHardwareTimer::CancelTask(&g_hardwareTimer, &this->KTimerTask) ) | |
this->DecrementRefcount(this); | |
this->signaled = 0; | |
this->allowedToRegister = 1; | |
KAutoObject::IncrementRefcount(this); | |
this->OnTimeout(this); | |
} | |
return 0; | |
} | |
// FFF10890: variable 'v3' is possibly undefined | |
//----- (FFF109A0) -------------------------------------------------------- | |
Result __fastcall KProcessPageTable::Initialize(KProcessPageTable *this, u32 pid, bool onlyUseSmallPages) | |
{ | |
unsigned int v5; // r2 | |
bool v6; // zf | |
unsigned int v7; // r3 | |
unsigned int index; // r0 | |
int v9; // r0 | |
unsigned int v10; // r1 | |
u8 v11; // r10 | |
u32 *Contiguous; // r8 | |
unsigned int v14; // r2 | |
int v15; // r0 | |
char cfgr; // r1 | |
int v17; // r1 | |
this->translationTableSize = 0x1000; | |
this->addressSpaceStart = 0; | |
this->addressSpaceEnd = 0x40000000; | |
this->linearAddressRangeStart = 0; | |
v5 = __ldrex((unsigned int *)&g_asidManager.mutex); | |
v6 = v5 == 0; | |
if ( v5 ) | |
v7 = __strex(v5, (unsigned int *)&g_asidManager.mutex); | |
else | |
v7 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_asidManager.mutex); | |
if ( !v5 ) | |
v6 = v7 == 0; | |
if ( !v6 ) | |
KLightMutex::LockImpl(&g_asidManager.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
index = g_asidManager.index; | |
if ( ((g_asidManager.map[index >> 5] >> (index & 0x1F)) & 1) != 0 ) | |
{ | |
v9 = 0; | |
while ( 1 ) | |
{ | |
v10 = __clz((g_asidManager.map[v9] + 1) & ~g_asidManager.map[v9]); | |
if ( v10 < 0x20 ) | |
break; | |
if ( ++v9 >= 8 ) | |
kernelpanic(); | |
} | |
index = (unsigned __int8)(31 - v10 + 32 * v9); | |
g_asidManager.index = index; | |
} | |
g_asidManager.map[index >> 5] |= 1 << (index & 0x1F); | |
v11 = index; | |
++g_asidManager.index; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_asidManager.mutex.lockingThread = 0; | |
if ( g_asidManager.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_asidManager.mutex); | |
this->asid = v11; | |
this->onlyUseSmallPages = onlyUseSmallPages; | |
this->isKernel = 0; | |
Contiguous = (u32 *)KMemoryManager::AllocateContiguous(&g_memoryManager, 1u, 1u, MEMOP_REGION_BASE_KERNEL); | |
if ( !Contiguous ) | |
return -664795149; | |
v14 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( v14 ) | |
{ | |
__strex(v14, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
} | |
else if ( !__strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex) ) | |
{ | |
goto LABEL_23; | |
} | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
LABEL_23: | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)Contiguous, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
KPageTable::InitizalizeL1Table(&this->L1Table, Contiguous); | |
this->translationTableBase = ((unsigned int)(Contiguous + 0x10000000) >> 9 << 9) | 0x12; | |
KMemoryBlockManager::Initialize(&this->memoryBlockMgr, this->addressSpaceStart, this->addressSpaceEnd); | |
KPageTable::CleanDataCacheRange( | |
(u32)&this->L1Table[this->addressSpaceStart >> 20], | |
4 * (this->translationTableSize >> 2)); | |
KPageTable::InvalidateAllTlbEntries(this); // tlbi | |
v15 = (int)g_tlbMaintenanceHelper.currentProcPageTables[0]; | |
if ( !g_tlbMaintenanceHelper.currentProcPageTables[0] ) | |
{ | |
cfgr = MPCORE.scu.cfgr; | |
v17 = (cfgr & 3) + 1; | |
while ( v17 > v15 ) | |
g_tlbMaintenanceHelper.currentProcPageTables[v15++] = this; | |
} | |
return 0; | |
} | |
//----- (FFF10BDC) -------------------------------------------------------- | |
Result __fastcall KProcessPageTable::ControlMemory( | |
KProcessPageTable *this, | |
u32 *outAddr, | |
u32 addr0, | |
u32 addr1, | |
u32 size, | |
u32 op, | |
u32 perms) | |
{ | |
int v8; // r5 | |
u32 v10; // r0 | |
u32 numPages; // r6 | |
u32 v12; // r8 | |
u32 i; // r3 | |
Result baseAddress; // r0 | |
unsigned __int32 v15; // r1 | |
u32 linearAllocAddr; // r0 | |
void *v17; // r9 | |
u8 v18; // r2 | |
u32 linearAddressRangeStart; // r0 | |
Result *p_result; // r0 | |
bool v21; // zf | |
KMemoryState state; // [sp+0h] [bp-60h] BYREF | |
u32 region; // [sp+4h] [bp-5Ch] BYREF | |
Result result; // [sp+8h] [bp-58h] BYREF | |
KMemoryState newStateDst; // [sp+10h] [bp-50h] | |
KMemoryPermission newPermsDst; // [sp+14h] [bp-4Ch] | |
KMemoryUpdateFlags v27; // [sp+18h] [bp-48h] | |
KMemoryInfo outMemoryInfo; // [sp+1Ch] [bp-44h] BYREF | |
v8 = addr0; | |
newStateDst = MEMSTATE_FREE; | |
v10 = perms & KMEMPERM_RW; | |
newPermsDst = v10 | KMEMPERM_KRW; // always writable by kernel, remove X bit | |
v27 = KMEMUPDATE_NONE; | |
numPages = size >> 12; | |
v12 = 0; | |
region = op & 0xF00; | |
switch ( (char)op ) | |
{ | |
case MEMOP_FREE: | |
for ( i = addr0; ; i = baseAddress + v15 ) | |
{ | |
if ( i >= v8 + size ) | |
{ | |
newStateDst = MEMSTATE_FREE; | |
goto LABEL_29; | |
} | |
baseAddress = KPageTable::QueryInfo(this, &outMemoryInfo, (u32 *)&state, i); | |
v15 = baseAddress & 0x80000000; | |
if ( baseAddress < 0 ) | |
break; | |
if ( (outMemoryInfo.state & KMEMSTATE_FLAG_DEALLOCATABLE) != 0 ) | |
{ | |
baseAddress = outMemoryInfo.baseAddress; | |
v15 = outMemoryInfo.size; | |
} | |
else | |
{ | |
baseAddress = 0xE0A01BF5; | |
} | |
if ( (outMemoryInfo.state & KMEMSTATE_FLAG_DEALLOCATABLE) == 0 ) | |
break; | |
} | |
break; | |
case MEMOP_ALLOC: | |
if ( !addr0 | |
|| (baseAddress = KPageTable::CheckAddressRangeSizeAndState(this, addr0, size, MEMSTATE_FREE), baseAddress >= 0) ) | |
{ | |
if ( (op & MEMOP_LINEAR_FLAG) == 0 ) | |
{ | |
newStateDst = KMEMSTATE_PRIVATE_DATA; | |
goto LABEL_29; | |
} | |
linearAllocAddr = KMemoryManager::AllocateContiguous(&g_memoryManager, numPages, 0, (MemoryOperation)region); | |
v17 = (void *)linearAllocAddr; | |
if ( !linearAllocAddr ) | |
{ | |
v18 = 3; | |
state = 0x3F3; | |
goto LABEL_20; | |
} | |
v12 = linearAllocAddr + 0x40000000; // - 0xC0000000 | |
linearAddressRangeStart = this->linearAddressRangeStart; | |
v8 = (int)v17 + linearAddressRangeStart + 0x20000000; | |
if ( linearAddressRangeStart == 0x14000000 && v8 + (numPages << 12) > 0x1C000000 ) | |
{ // oops, VA can't fit | |
KLightMutex::Lock((KLightMutex **)®ion, &g_memoryManager.pgMgr.mutex); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)v17, numPages); | |
KLightMutex::Unlock((KLightMutex *)region); | |
KMemoryManager::FreeContiguousLocked(&g_memoryManager, (u32)v17, numPages); | |
v18 = 3; | |
p_result = &result; | |
state = 0x3F3; | |
goto LABEL_23; | |
} | |
v21 = addr0 == 0; | |
if ( addr0 ) | |
v21 = v8 == addr0; | |
if ( v21 ) | |
{ | |
newStateDst = KMEMSTATE_LINEAR; | |
memset(v17, 0, numPages << 12); | |
KPageTable::CleanInvalidateDataCacheRange((u32)v17, numPages << 12); | |
goto LABEL_29; | |
} | |
KLightMutex::Lock((KLightMutex **)&state, &g_memoryManager.pgMgr.mutex);// linear alloc didn't match specified addr0 (!= 0), dealloc | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)v17, numPages); | |
KLightMutex::Unlock((KLightMutex *)state); | |
KMemoryManager::FreeContiguousLocked(&g_memoryManager, (u32)v17, numPages); | |
baseAddress = 0xE0E01BF5; | |
} | |
break; | |
case MEMOP_MAP: | |
baseAddress = KPageTable::CreateAlias( | |
this, | |
addr1, | |
addr0, | |
size >> 12, | |
KMEMSTATE_PRIVATE_DATA, | |
KMEMPERM_RW, | |
KMEMSTATE_ALIASED, | |
KMEMPERM_KRW_RW, | |
KMEMSTATE_ALIAS, | |
(KMemoryPermission)(v10 | KMEMPERM_KRW)); | |
break; | |
case MEMOP_UNMAP: | |
baseAddress = KPageTable::DestroyAlias( | |
this, | |
addr1, | |
addr0, | |
size >> 12, | |
KMEMSTATE_ALIASED, | |
KMEMPERM_NONE, | |
KMEMSTATE_ALIAS, | |
KMEMPERM_NONE, | |
KMEMSTATE_PRIVATE_DATA, | |
(KMemoryPermission)(v10 | KMEMPERM_KRW), | |
v27); | |
break; | |
case MEMOP_PROT: | |
baseAddress = KPageTable::CheckAddressRangeSizeAndStateFlags( | |
this, | |
addr0, | |
size, | |
KMEMSTATE_FLAG_PROTECTIBLE, | |
KMEMSTATE_FLAG_PROTECTIBLE); | |
if ( baseAddress >= 0 ) | |
{ | |
BYTE1(v27) = 1; | |
LABEL_29: | |
baseAddress = KPageTable::Operate(this, v8, numPages, v12, newStateDst, newPermsDst, v27, region); | |
if ( baseAddress >= 0 ) | |
{ | |
if ( outAddr ) | |
*outAddr = v8; | |
} | |
} | |
break; | |
default: | |
v18 = 7; | |
state = KMEMSTATE_FLAG_PROTECTIBLE|KMEMSTATE_FLAG_DEALLOCATABLE|MEMSTATE_ALIAS|MEMSTATE_CODE|0xE0; | |
LABEL_20: | |
p_result = (Result *)®ion; | |
LABEL_23: | |
baseAddress = *MakeResultCode(p_result, 0xFBu, v18, 1u, state);// 0x3ED | |
break; | |
} | |
return baseAddress; | |
} | |
// FFF10BDC: using guessed type u32 size; | |
// FFF10BDC: using guessed type u32 op; | |
//----- (FFF10F14) -------------------------------------------------------- | |
Result __fastcall KProcessPageTable::MapSharedConfigPages(KProcessPageTable *this, bool canWriteSharedUserPage) | |
{ | |
BOOL v3; // r6 | |
KMemoryPermission v4; // r6 | |
u32 mmuAttribs; // [sp+8h] [bp-20h] BYREF | |
v3 = canWriteSharedUserPage; | |
mmuAttribs = 0x5A5; // both uncacheable | |
KPageTable::MapContiguousPhysicalAddressRange( | |
this, | |
0x1FF80000u, | |
(u32)&g_kernelSharedConfigPagePtr[0x40000], | |
1u, | |
&mmuAttribs); | |
KMemoryBlockManager::MutateRange(&this->memoryBlockMgr, 0x1FF80000u, 1u, KMEMSTATE_SHARED, KMEMPERM_KRW_R, 0); | |
if ( v3 ) | |
mmuAttribs = 0xDB5; | |
else | |
mmuAttribs = 0xDA5; | |
if ( v3 ) | |
v4 = KMEMPERM_KRW_RW; | |
else | |
v4 = KMEMPERM_KRW_R; | |
KPageTable::MapContiguousPhysicalAddressRange( | |
this, | |
0x1FF81000u, | |
g_userSharedConfigPagePtr - 0xC0000000, | |
1u, | |
&mmuAttribs); | |
KMemoryBlockManager::MutateRange(&this->memoryBlockMgr, 0x1FF81000u, 1u, KMEMSTATE_SHARED, v4, 0); | |
KPageTable::InvalidateAllTlbEntries(this); | |
return 0; | |
} | |
// FFF2F0D4: using guessed type KernelSharedConfig *g_kernelSharedConfigPagePtr; | |
//----- (FFF11008) -------------------------------------------------------- | |
Result __fastcall KPageTable::CheckAndUpdateAddrRangeMaskedStateAndPerms( | |
KPageTable *this, | |
u32 addr, | |
u32 numPages, | |
KMemoryState stateMask, | |
KMemoryState expectedState, | |
KMemoryPermission minPerms, | |
KMemoryState newState, | |
KMemoryPermission newPerms) | |
{ | |
Result result; // r0 | |
result = KPageTable::CheckAddrRangeMaskedStateAndPerms(this, addr, numPages << 12, stateMask, expectedState, minPerms); | |
if ( result >= 0 ) | |
return KPageTable::Operate(this, addr, numPages, 0, newState, newPerms, KMEMUPDATE_STATE_AND_PERMS, 0x300u); | |
return result; | |
} | |
//----- (FFF1107C) -------------------------------------------------------- | |
Result __fastcall KInterruptManager::UnbindUserInterruptEventChecked( | |
KInterruptManager *this, | |
KInterruptEvent *interruptEvent, | |
s32 irqId) | |
{ | |
KLightMutex *p_mutex; // r0 | |
KLightMutex *v7; // r4 | |
unsigned int v8; // r2 | |
bool v9; // zf | |
unsigned int v10; // r3 | |
u32 v12; // r0 | |
KInterruptHandler *v13; // r1 | |
KInterruptEntry *v14; // r7 | |
bool v15; // zf | |
int v16; // r0 | |
Result v17; // r7 | |
p_mutex = &this->mutex; | |
v7 = p_mutex; | |
v8 = __ldrex((unsigned int *)p_mutex); | |
v9 = v8 == 0; | |
if ( v8 ) | |
v10 = __strex(v8, (unsigned int *)p_mutex); | |
else | |
v10 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)p_mutex); | |
if ( !v8 ) | |
v9 = v10 == 0; | |
if ( !v9 ) | |
KLightMutex::LockImpl(p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( (unsigned int)(irqId - 32) <= 0x5F ) | |
{ | |
v12 = irqId; | |
if ( interruptEvent ) | |
v13 = &interruptEvent->KInterruptTask; | |
else | |
v13 = 0; | |
v14 = &this->privateInterrupts[3][irqId]; | |
v15 = v13 == 0; | |
if ( v13 ) | |
v15 = v14->handler == v13; | |
if ( v15 ) | |
{ | |
KInterruptController::DisableInterrupt(v12); | |
v16 = 0; | |
v14->handler = 0; | |
} | |
else | |
{ | |
v16 = 0xD8E007F0; | |
} | |
v17 = v16; | |
if ( v16 >= 0 ) | |
{ | |
interruptEvent->irqId = -1; | |
interruptEvent->DecrementRefcount(interruptEvent); | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
v7->lockingThread = 0; | |
if ( v7->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v7); | |
return v17; | |
} | |
else | |
{ | |
__mcr(15, 0, 0, 7, 10, 5); | |
v7->lockingThread = 0; | |
if ( v7->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v7); | |
return 0xD8E007FD; | |
} | |
} | |
//----- (FFF11178) -------------------------------------------------------- | |
Result __fastcall KInterruptManager::BindUserInterruptEvent( | |
KInterruptManager *this, | |
KInterruptEvent *interruptEvent, | |
s32 irqId, | |
s32 coreId, | |
s32 priority, | |
bool manualClear, | |
bool levelSensitive) | |
{ | |
unsigned int *p_mutex; // r0 | |
KLightMutex *v11; // r4 | |
unsigned int v12; // r2 | |
bool v13; // zf | |
unsigned int v14; // r3 | |
KInterruptTask *v16; // r1 | |
int v17; // r6 | |
p_mutex = (unsigned int *)&this->mutex; | |
v11 = (KLightMutex *)p_mutex; | |
v12 = __ldrex(p_mutex); | |
v13 = v12 == 0; | |
if ( v12 ) | |
v14 = __strex(v12, p_mutex); | |
else | |
v14 = __strex((unsigned int)current.clc.current.thread, p_mutex); | |
if ( !v12 ) | |
v13 = v14 == 0; | |
if ( !v13 ) | |
KLightMutex::LockImpl((KLightMutex *)p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( (unsigned int)(irqId - 32) <= 0x5F ) | |
{ | |
KAutoObject::IncrementRefcount(interruptEvent); | |
interruptEvent->irqId = irqId; | |
if ( interruptEvent ) | |
v16 = &interruptEvent->KInterruptTask; | |
if ( !interruptEvent ) | |
v16 = 0; | |
v17 = KInterruptManager::BindSharedInterrupt(this, v16, irqId, coreId, priority, manualClear, levelSensitive); | |
if ( v17 < 0 ) | |
{ | |
interruptEvent->irqId = -1; | |
interruptEvent->DecrementRefcount(interruptEvent); | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
v11->lockingThread = 0; | |
if ( v11->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v11); | |
return v17; | |
} | |
else | |
{ | |
__mcr(15, 0, 0, 7, 10, 5); | |
v11->lockingThread = 0; | |
if ( v11->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v11); | |
return -656406531; | |
} | |
} | |
// FFF11220: variable 'v16' is possibly undefined | |
//----- (FFF11274) -------------------------------------------------------- | |
void __fastcall KMemoryBlockManager::Initialize(KMemoryBlockManager *this, u32 addrSpaceStart, u32 addrSpaceEnd) | |
{ | |
KMemoryBlock *v6; // r4 | |
KLinkedListNode *v7; // r0 | |
v6 = (KMemoryBlock *)KSlabHeap::Allocate(&g_memoryBlockSlabHeap); | |
v6->perms = KMEMPERM_NONE; | |
v6->numPages = (addrSpaceEnd - addrSpaceStart) >> 12; | |
v6->baseAddr = addrSpaceStart; | |
v6->state = MEMSTATE_FREE; | |
v6->tag = 0; | |
v7 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v7 ) | |
{ | |
v7->link.next = 0; | |
v7->link.prev = 0; | |
v7->data = 0; | |
} | |
v7->data = v6; | |
KLinkedList::InsertAfter((KLinkedList *)this, (KLinkedListLink *)&this->blocks.link, v7); | |
} | |
// FFF112EC: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF1131C) -------------------------------------------------------- | |
void __fastcall KInterruptController::EnableWithPriority(s32 irqId, u8 priority) | |
{ | |
*(_BYTE *)(irqId + 0xFFFEF400) = 16 * priority; | |
if ( (unsigned int)(irqId - 16) <= 0x6F ) | |
MPCORE.gicd.isenabler[irqId / 32] = 1 << (irqId % 32); | |
} | |
//----- (FFF11364) -------------------------------------------------------- | |
u32 KPerformanceCounterManager::GetOverflowFlags(void) | |
{ | |
unsigned int cpuEvtOvf; // r2 | |
u32 pmncr; // r1 | |
cpuEvtOvf = __mrc(15, 0, 15, 12, 0) & 0x700; | |
pmncr = MPCORE.scu.pmncr; | |
return (cpuEvtOvf >> 8) | pmncr & 0xFF0000; | |
} | |
//----- (FFF11388) -------------------------------------------------------- | |
void __fastcall KPerformanceCounterManager::SetVirtualCounterEnabled(KPerformanceCounterManager *this, bool enable) | |
{ | |
int v3; // r7 | |
int i; // r4 | |
int v5; // r6 | |
int j; // r4 | |
int v7; // r1 | |
int v8; // r2 | |
KInterruptHandler_vtbl **v9; // r2 | |
int v10; // r2 | |
if ( this->virtualCounterEnabled != enable ) | |
{ | |
if ( enable ) | |
{ | |
KPerformanceCounterManager::BindInterrupts(this); | |
} | |
else | |
{ | |
v3 = __mrc(15, 0, 0, 0, 5) & 3; | |
for ( i = 0; i < 4; ++i ) | |
KInterruptManager::UnbindKernelInterruptForCore(&g_interruptManager, i + 120, v3); | |
if ( KSystemControl::IsLgr2Capable() ) | |
v5 = 124; | |
else | |
v5 = 122; | |
for ( j = 0; j < 8; ++j ) | |
KInterruptManager::UnbindKernelInterruptForCore(&g_interruptManager, v5 + j, v3); | |
v7 = 0; | |
this->virtualCounterEnabled = 0; | |
while ( 1 ) | |
{ | |
v10 = (MPCORE.scu.cfgr & 3) + 1; | |
if ( v10 <= v7 ) | |
break; | |
v8 = 3 * v7++; | |
v9 = &(&this->__vftable)[v8]; | |
v9[1] = 0; | |
v9[2] = 0; | |
v9[3] = 0; | |
} | |
this->scuCounterHi[0] = 0; | |
this->scuCounterHi[1] = 0; | |
this->scuCounterHi[2] = 0; | |
this->scuCounterHi[3] = 0; | |
this->scuCounterHi[4] = 0; | |
this->scuCounterHi[5] = 0; | |
this->scuCounterHi[6] = 0; | |
this->scuCounterHi[7] = 0; | |
} | |
} | |
} | |
//----- (FFF11474) -------------------------------------------------------- | |
void __fastcall KPerformanceCounterManager::ResetCounters( | |
KPerformanceCounterManager *this, | |
u32 valueMask, | |
u32 overflowMask) | |
{ | |
KPerformanceCounterManager *reused; // r4 | |
unsigned int CPSR; // r12 | |
unsigned int v5; // r5 | |
bool v6; // zf | |
signed __int32 v7; // r2 | |
u32 pmncr; // r12 | |
unsigned int v9; // r12 | |
KInterruptHandler_vtbl **v10; // r2 | |
if ( ((valueMask | overflowMask) & 7) != 0 ) | |
{ | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
reused = (KPerformanceCounterManager *)((char *)this + 12 * (__mrc(15, 0, 0, 0, 5) & 3)); | |
v5 = (overflowMask << 8) & 0x700 | __mrc(15, 0, 15, 12, 0) & 0xFFFFF8FF | valueMask & 4; | |
reused->cp15CounterHi[0][2] = 0; | |
if ( (~valueMask & 3) != 0 ) | |
{ | |
if ( (valueMask & 1) != 0 ) | |
__mcr(15, 0, 0, 15, 12, 2); | |
if ( (valueMask & 1) != 0 ) | |
reused->cp15CounterHi[0][0] = 0; | |
if ( (valueMask & 2) == 0 ) | |
goto LABEL_12; | |
__mcr(15, 0, 0, 15, 12, 3); | |
} | |
else | |
{ | |
v5 |= 2u; // reset both using P bit | |
reused->cp15CounterHi[0][0] = 0; | |
} | |
reused->cp15CounterHi[0][1] = 0; | |
LABEL_12: | |
__mcr(15, 0, v5, 15, 12, 0); | |
__set_CPSR(CPSR); | |
} | |
if ( (valueMask | overflowMask) << 8 >> 24 ) | |
{ | |
v6 = (unsigned __int8)~BYTE2(valueMask) == 0; | |
v7 = overflowMask & 0xFF0000; | |
pmncr = MPCORE.scu.pmncr; | |
if ( BYTE2(valueMask) == 0xFF ) | |
valueMask = 0; | |
else | |
reused = (KPerformanceCounterManager *)MPCORE.scu.mnr; | |
v9 = pmncr & 0xFF00FFFF | v7; | |
if ( v6 ) | |
v9 |= 2u; | |
else | |
v7 = 0; // similar thing, with "reset all" vs "reset some" | |
if ( v6 ) | |
{ | |
do | |
{ | |
v10 = &(&this->__vftable)[valueMask++]; | |
v10[13] = 0; | |
} | |
while ( (int)valueMask < 8 ); | |
} | |
else | |
{ | |
do | |
{ | |
if ( ((valueMask >> (v7 + 16)) & 1) != 0 ) | |
{ | |
(&reused->__vftable)[v7] = 0; | |
this->scuCounterHi[v7] = 0; | |
} | |
++v7; | |
} | |
while ( v7 < 8 ); | |
} | |
MPCORE.scu.pmncr = v9; | |
} | |
} | |
// FFF1154C: variable 'reused' is possibly undefined | |
//----- (FFF1158C) -------------------------------------------------------- | |
void __fastcall KPerformanceCounterManager::Enable(KPerformanceCounterManager *this) | |
{ | |
int i; // r1 | |
KPerformanceCounterControlHelper *v3; // r2 | |
int v4; // r12 | |
__int32 v5; // r0 | |
int j; // r2 | |
int k; // r1 | |
KPerformanceCounterManager *v8; // lr | |
KPerformanceCounterManager::BindInterrupts(this); | |
this->cp15CounterHi[0][0] = 0; | |
this->cp15CounterHi[0][1] = 0; | |
this->cp15CounterHi[0][2] = 0; | |
this->cp15CounterHi[1][0] = 0; | |
this->cp15CounterHi[1][1] = 0; | |
this->cp15CounterHi[1][2] = 0; | |
this->cp15CounterHi[2][0] = 0; | |
this->cp15CounterHi[2][1] = 0; | |
this->cp15CounterHi[2][2] = 0; | |
this->cp15CounterHi[3][0] = 0; | |
this->cp15CounterHi[3][1] = 0; | |
this->cp15CounterHi[3][2] = 0; | |
g_perfCounterControlHelper.pmncCp15Value = 0x777;// | |
// - Enable | |
// - Reset Count Register on write | |
// - Reset Cycle Count Register on write | |
// - Enable all 3 interrupts | |
// - Clear all 3 overflow flags | |
for ( i = 0; ; ++i ) | |
{ | |
v4 = (MPCORE.scu.cfgr & 3) + 1; | |
if ( v4 <= i ) | |
break; | |
v3 = (KPerformanceCounterControlHelper *)((char *)&g_perfCounterControlHelper + i); | |
v3->writeCompleted[0] = 0; | |
} | |
v5 = (((1 << ((MPCORE.scu.cfgr & 3) + 1)) - 1) << 16) & 0xFF0000 | KINTNAME_SGI_PERFCOUNTERCTRL; | |
MPCORE.gicd.sgir = v5; | |
for ( j = 0; v4 > j; ++j ) | |
{ | |
while ( !g_perfCounterControlHelper.writeCompleted[j] ) | |
; | |
} | |
MPCORE.scu.pmncr = 0xFF0002; // reset counters, disable interrupt, clear overflow flags (by writing 1) | |
for ( k = 0; k < 8; ++k ) | |
{ | |
v8 = (KPerformanceCounterManager *)((char *)this + 4 * k); | |
*(_BYTE *)(((unsigned int)&MPCORE.scu.pmncr | 0x1FE0004) + k) = 0;// Monitor Counter Events | |
*(_DWORD *)(((unsigned int)&MPCORE.scu.pmncr | 0x1FE0004) + 8 + 4 * k) = 0;// Monitor Counter registers | |
v8->scuCounterHi[0] = 0; | |
} | |
MPCORE.scu.pmncr = 0xFFFF03; // enable, reset counters, enable interrupts, clear interrupt flags | |
} | |
//----- (FFF116B8) -------------------------------------------------------- | |
void KPerformanceCounterManager::Disable(void) | |
{ | |
int v0; // r6 | |
int i; // r4 | |
int v2; // r5 | |
int j; // r4 | |
int k; // r1 | |
char *v5; // r3 | |
int v6; // r3 | |
int m; // r0 | |
v0 = __mrc(15, 0, 0, 0, 5) & 3; | |
for ( i = 0; i < 4; ++i ) | |
KInterruptManager::UnbindKernelInterruptForCore(&g_interruptManager, i + 120, v0); | |
if ( KSystemControl::IsLgr2Capable() ) | |
v2 = 124; | |
else | |
v2 = 122; | |
for ( j = 0; j < 8; ++j ) | |
KInterruptManager::UnbindKernelInterruptForCore(&g_interruptManager, v2 + j, v0); | |
g_perfCounterControlHelper.pmncCp15Value = 0x706;// | |
// - bit0 unset: disable all counters | |
// - bit1: reset all counters | |
// - bit2: Reserved SBZ but assigned to 1??? (might be related to N3DS) | |
// - bit7+: MN0, 1, 2 interrupts enabled | |
// - bit16+ unset: overflow flags cleared | |
for ( k = 0; ; ++k ) | |
{ | |
v6 = (MPCORE.scu.cfgr & 3) + 1; | |
if ( v6 <= k ) | |
break; | |
v5 = (char *)&g_perfCounterControlHelper + k; | |
v5[4] = 0; | |
} | |
MPCORE.gicd.sgir = (((1 << ((MPCORE.scu.cfgr & 3) + 1)) - 1) << 16) & 0xFF0000 | 4; | |
for ( m = 0; v6 > m; ++m ) | |
{ | |
while ( !g_perfCounterControlHelper.writeCompleted[m] ) | |
; | |
} | |
MPCORE.scu.pmncr = 0xFF0002; // reset counters, disable interrupt, set overflow flags????? | |
} | |
//----- (FFF117D8) -------------------------------------------------------- | |
PerformanceCounterEvent __fastcall KPerformanceCounterManager::GetEvent( | |
KPerformanceCounterManager *this, | |
PerformanceCounterName name) | |
{ | |
bool v2; // zf | |
u32 cfgr; // r2 | |
if ( name == PERFCOUNTER_NAME_SCU_2 ) | |
goto LABEL_14; | |
if ( name >= PERFCOUNTER_NAME_SCU_2 ) | |
{ | |
if ( (unsigned int)(name - PERFCOUNTER_NAME_SCU_3) > 4 ) | |
return 0; | |
LABEL_14: | |
cfgr = MPCORE.scu.cfgr; | |
if ( (int)(((2 * cfgr) & 7) + 2) > name - PERFCOUNTER_NAME_SCU_0 ) | |
return *((unsigned __int8 *)&MPCORE.scu.cfgr + name) + PERFCOUNTEREVENT_SCU_BASE; | |
return 0; | |
} | |
if ( name == PERFCOUNTER_NAME_CORE_CYCLE_COUNTER ) | |
{ | |
if ( (__mrc(15, 0, 15, 12, 0) & 8) != 0 ) | |
return 4095; // fake event | |
else | |
return 255; | |
} | |
if ( name >= PERFCOUNTER_NAME_CORE_CYCLE_COUNTER ) | |
{ | |
v2 = name == PERFCOUNTER_NAME_SCU_0; | |
if ( name != PERFCOUNTER_NAME_SCU_0 ) | |
v2 = name == PERFCOUNTER_NAME_SCU_1; | |
if ( !v2 ) | |
return 0; | |
goto LABEL_14; | |
} | |
if ( name ) | |
{ | |
if ( name == PERFCOUNTER_NAME_CORE_COUNT_REG_1 ) | |
return (__mrc(15, 0, 15, 12, 0) & 0xFF000u) >> 12; | |
return 0; | |
} | |
return (__mrc(15, 0, 15, 12, 0) & 0xFF00000u) >> 20; | |
} | |
//----- (FFF11890) -------------------------------------------------------- | |
u64 __fastcall KPerformanceCounterManager::GetCounterValue( | |
KPerformanceCounterManager *this, | |
PerformanceCounterName name) | |
{ | |
bool v3; // zf | |
int v4; // r0 | |
u32 cfgr; // r1 | |
KPerformanceCounterManager *v6; // r1 | |
unsigned int CPSR; // r2 | |
unsigned int v8; // r2 | |
u64 result; // r0 | |
if ( name == PERFCOUNTER_NAME_SCU_2 ) | |
goto LABEL_14; | |
if ( name > PERFCOUNTER_NAME_SCU_2 ) | |
{ | |
if ( (unsigned int)(name - PERFCOUNTER_NAME_SCU_3) > 4 ) | |
return 0LL; | |
LABEL_14: | |
v4 = name - 16; | |
cfgr = MPCORE.scu.cfgr; | |
if ( (int)(((2 * cfgr) & 7) + 2) > v4 ) | |
{ | |
v6 = (KPerformanceCounterManager *)((char *)this + 4 * v4); | |
LODWORD(result) = MPCORE.scu.mnr[v4]; | |
HIDWORD(result) = v6->scuCounterHi[0]; | |
return result; | |
} | |
return 0LL; | |
} | |
if ( name == PERFCOUNTER_NAME_CORE_CYCLE_COUNTER ) | |
{ | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
LODWORD(result) = __mrc(15, 0, 15, 12, 1); | |
HIDWORD(result) = this->cp15CounterHi[__mrc(15, 0, 0, 0, 5) & 3][2]; | |
__set_CPSR(CPSR); | |
return result; | |
} | |
if ( name > PERFCOUNTER_NAME_CORE_CYCLE_COUNTER ) | |
{ | |
v3 = name == PERFCOUNTER_NAME_SCU_0; | |
if ( name != PERFCOUNTER_NAME_SCU_0 ) | |
v3 = name == PERFCOUNTER_NAME_SCU_1; | |
if ( !v3 ) | |
return 0LL; | |
goto LABEL_14; | |
} | |
if ( name == PERFCOUNTER_NAME_CORE_COUNT_REG_0 ) | |
{ | |
v8 = __get_CPSR(); | |
__disable_irq(); | |
LODWORD(result) = __mrc(15, 0, 15, 12, 2); | |
HIDWORD(result) = this->cp15CounterHi[__mrc(15, 0, 0, 0, 5) & 3][0]; | |
goto LABEL_18; | |
} | |
if ( name == PERFCOUNTER_NAME_CORE_COUNT_REG_1 ) | |
{ | |
v8 = __get_CPSR(); | |
__disable_irq(); | |
LODWORD(result) = __mrc(15, 0, 15, 12, 3); | |
HIDWORD(result) = this->cp15CounterHi[__mrc(15, 0, 0, 0, 5) & 3][1]; | |
LABEL_18: | |
__set_CPSR(v8); | |
return result; | |
} | |
return 0LL; | |
} | |
//----- (FFF11994) -------------------------------------------------------- | |
void __fastcall KPerformanceCounterManager::SetEvent( | |
KPerformanceCounterManager *this, | |
PerformanceCounterName name, | |
PerformanceCounterEvent event) | |
{ | |
unsigned int v3; // r0 | |
bool v4; // zf | |
u32 cfgr; // r3 | |
unsigned int CPSR; // r0 | |
unsigned int v7; // r1 | |
unsigned int v8; // r1 | |
if ( name == PERFCOUNTER_NAME_SCU_2 ) | |
goto LABEL_15; | |
if ( name >= PERFCOUNTER_NAME_SCU_2 ) | |
{ | |
if ( (unsigned int)(name - 19) > 4 ) | |
return; | |
goto LABEL_15; | |
} | |
if ( name == PERFCOUNTER_NAME_CORE_CYCLE_COUNTER ) | |
{ | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
v7 = __mrc(15, 0, 15, 12, 0) & 0xFFFFF8FF; | |
if ( event == PERFCOUNTEREVENT_CORE_CYCLE_COUNT_64 )// fake event | |
v8 = v7 | 8; // change the cycle divider according to the event | |
else | |
v8 = v7 & ~8u; | |
__mcr(15, 0, v8, 15, 12, 0); | |
__set_CPSR(CPSR); | |
return; | |
} | |
if ( name >= PERFCOUNTER_NAME_CORE_CYCLE_COUNTER ) | |
{ | |
v4 = name == PERFCOUNTER_NAME_SCU_0; | |
if ( name != PERFCOUNTER_NAME_SCU_0 ) | |
v4 = name == PERFCOUNTER_NAME_SCU_1; | |
if ( !v4 ) | |
return; | |
LABEL_15: | |
cfgr = MPCORE.scu.cfgr; | |
if ( (int)(((2 * cfgr) & 7) + 2) > name - PERFCOUNTER_NAME_SCU_0 ) | |
*((_BYTE *)&MPCORE.scu.cfgr + name) = event; | |
return; | |
} | |
if ( name ) | |
{ | |
if ( name != PERFCOUNTER_NAME_CORE_COUNT_REG_1 ) | |
return; | |
v3 = __get_CPSR(); | |
__disable_irq(); | |
__mcr(15, 0, __mrc(15, 0, 15, 12, 0) & 0xFFF008FF | (event << 12) & 0xFF000, 15, 12, 0); | |
} | |
else | |
{ | |
v3 = __get_CPSR(); | |
__disable_irq(); | |
__mcr(15, 0, __mrc(15, 0, 15, 12, 0) & 0xF00FF8FF | (event << 20) & 0xFF00000, 15, 12, 0); | |
} | |
__set_CPSR(v3); | |
} | |
//----- (FFF11A84) -------------------------------------------------------- | |
void __fastcall KPerformanceCounterManager::SetCounterValue( | |
KPerformanceCounterManager *this, | |
PerformanceCounterName name, | |
u64 value) | |
{ | |
unsigned int v3; // r1 | |
bool v4; // zf | |
int v5; // r1 | |
u32 cfgr; // r12 | |
unsigned int CPSR; // r1 | |
if ( name == PERFCOUNTER_NAME_SCU_2 ) | |
goto LABEL_18; | |
if ( name > PERFCOUNTER_NAME_SCU_2 ) | |
{ | |
if ( (unsigned int)(name - PERFCOUNTER_NAME_SCU_3) > 4 ) | |
return; | |
goto LABEL_18; | |
} | |
if ( name == PERFCOUNTER_NAME_CORE_CYCLE_COUNTER ) | |
{ | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
if ( this->virtualCounterEnabled ) | |
this->cp15CounterHi[__mrc(15, 0, 0, 0, 5) & 3][PERFCOUNTER_NAME_CORE_CYCLE_COUNTER] = HIDWORD(value); | |
__mcr(15, 0, value, 15, 12, 1); | |
__set_CPSR(CPSR); | |
return; | |
} | |
if ( name >= PERFCOUNTER_NAME_CORE_CYCLE_COUNTER ) | |
{ | |
v4 = name == PERFCOUNTER_NAME_SCU_0; | |
if ( name != PERFCOUNTER_NAME_SCU_0 ) | |
v4 = name == PERFCOUNTER_NAME_SCU_1; | |
if ( !v4 ) | |
return; | |
LABEL_18: | |
v5 = name - PERFCOUNTER_NAME_SCU_0; | |
cfgr = MPCORE.scu.cfgr; | |
if ( (int)(((2 * cfgr) & 7) + 2) > v5 ) | |
{ | |
if ( this->virtualCounterEnabled ) | |
this->scuCounterHi[v5] = HIDWORD(value); | |
MPCORE.scu.mnr[v5] = value; | |
} | |
return; | |
} | |
if ( name ) | |
{ | |
if ( name != PERFCOUNTER_NAME_CORE_COUNT_REG_1 ) | |
return; | |
v3 = __get_CPSR(); | |
__disable_irq(); | |
if ( this->virtualCounterEnabled ) | |
this->cp15CounterHi[__mrc(15, 0, 0, 0, 5) & 3][1] = HIDWORD(value); | |
__mcr(15, 0, value, 15, 12, 3); | |
} | |
else | |
{ | |
v3 = __get_CPSR(); | |
__disable_irq(); | |
if ( this->virtualCounterEnabled ) | |
this->cp15CounterHi[__mrc(15, 0, 0, 0, 5) & 3][0] = HIDWORD(value); | |
__mcr(15, 0, value, 15, 12, 2); | |
} | |
__set_CPSR(v3); | |
} | |
//----- (FFF11BA4) -------------------------------------------------------- | |
void __fastcall KPageTable::InvalidateEntireInstructionCache() | |
{ | |
bool v0[8]; // [sp+0h] [bp-8h] BYREF | |
KCacheMaintenanceHelper::RequestOtherCoresEntireCacheMaintenance(v0, KCACHEMAINTOP_INV_ICACHE); | |
__mcr(15, 0, 0, 7, 5, 0); | |
__mcr(15, 0, 0, 7, 5, 6); | |
__mcr(15, 0, 0, 7, 10, 4); | |
__mcr(15, 0, 0, 7, 5, 4); | |
KCacheMaintenanceHelper::Join(v0); | |
} | |
//----- (FFF11BD4) -------------------------------------------------------- | |
Result __fastcall KProcessPageTable::CopyMemoryForDebug( | |
KProcessPageTable *this, | |
u32 dstAddr, | |
KProcessPageTable *srcPgTbl, | |
u32 srcAddr, | |
u32 size) | |
{ | |
unsigned int v9; // r2 | |
bool v10; // zf | |
unsigned int v11; // r1 | |
bool v12; // zf | |
unsigned int v13; // r2 | |
int v14; // r9 | |
bool v15; // zf | |
Result result; // r0 | |
KCopyMemoryForDebugHelper *v17; // r4 | |
u32 v18; // r6 | |
u32 v19; // r8 | |
u32 v20; // r4 | |
u32 v21; // r1 | |
KProcessPageTable *pgTblPtr; // r6 | |
unsigned int v23; // r1 | |
bool v24; // zf | |
unsigned int v25; // r2 | |
u32 v26; // r0 | |
u32 v27; // r0 | |
u32 v28; // r6 | |
u32 v29; // r1 | |
u32 v30; // r0 | |
u32 v31; // r1 | |
u32 v32; // r6 | |
unsigned int v33; // r0 | |
u32 v34; // r1 | |
u32 v35; // r6 | |
u32 v36; // r0 | |
u32 v37; // r1 | |
u32 v38; // r6 | |
u32 v39; // r1 | |
u32 v40; // r1 | |
u32 v41; // r0 | |
u32 v42; // r4 | |
u32 v43; // r6 | |
u32 v44; // r1 | |
u32 v45; // r4 | |
u32 v46; // r6 | |
const void *v47; // r1 | |
KTranslationTableIterator ttblIterator; // [sp+18h] [bp-88h] BYREF | |
u32 pa; // [sp+20h] [bp-80h] | |
u32 perms; // [sp+24h] [bp-7Ch] | |
KMemoryUpdateFlags v51; // [sp+28h] [bp-78h] | |
KTranslationTableIterator v52; // [sp+30h] [bp-70h] BYREF | |
KCopyMemoryForDebugHelper v53; // [sp+38h] [bp-68h] BYREF | |
u32 v54; // [sp+50h] [bp-50h] | |
KCopyMemoryForDebugHelper v55; // [sp+58h] [bp-48h] BYREF | |
u32 v56; // [sp+74h] [bp-2Ch] | |
v55.pgTblPtr = this; | |
v9 = __ldrex((unsigned int *)this); | |
v10 = v9 == 0; | |
if ( v9 ) | |
__strex(v9, (unsigned int *)this); | |
else | |
v9 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)this); | |
if ( v10 ) | |
v10 = v9 == 0; | |
if ( !v10 ) | |
KLightMutex::LockImpl(&this->mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KTranslationTableIterator::CreateFromEntry(&this->L1Table, &ttblIterator, &v55.traversalContext, dstAddr); | |
__mcr(15, 0, 0, 7, 10, 5); | |
this->mutex.lockingThread = 0; | |
if ( this->mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&this->mutex); | |
v53.pgTblPtr = srcPgTbl; | |
v55.pa = ttblIterator.pa; | |
v55.size = ttblIterator.size - (ttblIterator.pa & (ttblIterator.size - 1)); | |
v11 = __ldrex((unsigned int *)srcPgTbl); | |
v12 = v11 == 0; | |
if ( v11 ) | |
v13 = __strex(v11, (unsigned int *)srcPgTbl); | |
else | |
v13 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)srcPgTbl); | |
if ( !v11 ) | |
v12 = v13 == 0; | |
if ( !v12 ) | |
KLightMutex::LockImpl(&srcPgTbl->mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KTranslationTableIterator::CreateFromEntry(&srcPgTbl->L1Table, &ttblIterator, &v53.traversalContext, srcAddr); | |
__mcr(15, 0, 0, 7, 10, 5); | |
srcPgTbl->mutex.lockingThread = 0; | |
if ( srcPgTbl->mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&srcPgTbl->mutex); | |
v14 = 0; | |
v53.pa = ttblIterator.pa; | |
v53.size = ttblIterator.size - (ttblIterator.pa & (ttblIterator.size - 1)); | |
v15 = v55.pa == 0; | |
if ( v55.pa ) | |
v15 = v53.pa == 0; | |
if ( v15 ) | |
{ | |
if ( size ) | |
return 0xE0A01BF5; | |
return 0; | |
} | |
while ( 1 ) | |
{ | |
if ( v55.size > v53.size ) // check which block is smaller because of VA alignment | |
v17 = &v53; | |
else | |
v17 = &v55; | |
if ( v55.size <= v53.size ) | |
dstAddr = (u32)&v53; | |
if ( v55.size > v53.size ) | |
dstAddr = (u32)&v55; | |
if ( v17->size + v14 >= size ) | |
break; | |
pgTblPtr = v17->pgTblPtr; | |
v23 = __ldrex((unsigned int *)v17->pgTblPtr); | |
v24 = v23 == 0; | |
if ( v23 ) | |
v25 = __strex(v23, (unsigned int *)pgTblPtr); | |
else | |
v25 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)pgTblPtr); | |
if ( !v23 ) | |
v24 = v25 == 0; | |
if ( !v24 ) | |
KLightMutex::LockImpl(&pgTblPtr->mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KTranslationTableIterator::Advance(&pgTblPtr->L1Table, &v52, &v17->traversalContext); | |
__mcr(15, 0, 0, 7, 10, 5); | |
pgTblPtr->mutex.lockingThread = 0; | |
if ( pgTblPtr->mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&pgTblPtr->mutex); | |
v26 = v17->size; | |
if ( v17->pa + v26 == v52.pa ) | |
{ | |
v27 = v26 + v52.size; | |
} | |
else | |
{ | |
perms = v17->size; | |
v28 = v53.pa; | |
if ( v55.pa - 0x20000000 < 0x10000000 ) | |
goto LABEL_167; | |
v29 = v55.pa >> 12 << 12; | |
ttblIterator.pa = perms + v55.pa - v29; | |
if ( v29 - 0x18000000 > 0x600000 ) | |
{ | |
if ( v29 - 0x1F000000 > 0x400000 ) | |
{ | |
if ( v29 - 0x10100000 > 0x1000000 ) | |
{ | |
if ( v29 - 0x1FF00000 > 0x80000 ) | |
v29 = 0; | |
} | |
else | |
{ | |
v29 = (v55.pa >> 12 << 12) + 0xEB00000; | |
} | |
} | |
else | |
{ | |
v29 -= 0x800000; | |
} | |
} | |
else | |
{ | |
v29 += 0x7000000; | |
} | |
result = KProcessPageTable::MapStaticOrIo(srcPgTbl, v29, (ttblIterator.pa + 4095) >> 12, 1, KMEMPERM_RW); | |
if ( result >= 0 ) | |
{ | |
LABEL_167: | |
if ( v28 - 0x20000000 < 0x10000000 ) | |
goto LABEL_75; | |
v30 = v28 >> 12 << 12; | |
v31 = v28 - v30; | |
v32 = v30; | |
v33 = v30 - 402653184; | |
v34 = v31 + perms; | |
if ( v33 <= 0x600000 ) | |
v32 += 117440512; | |
if ( v33 > 0x600000 ) | |
{ | |
if ( v32 - 0x1F000000 > 0x400000 ) | |
{ | |
if ( v32 - 0x10100000 > 0x1000000 ) | |
{ | |
if ( v32 - 0x1FF00000 > 0x80000 ) | |
v32 = 0; | |
} | |
else | |
{ | |
v32 += 0xEB00000; | |
} | |
} | |
else | |
{ | |
v32 -= 0x800000; | |
} | |
} | |
result = KProcessPageTable::MapStaticOrIo(this, v32, (v34 + 4095) >> 12, 1, KMEMPERM_RW); | |
if ( result >= 0 ) | |
LABEL_75: | |
result = 0; | |
} | |
if ( result < 0 ) | |
return result; | |
v35 = v53.pa; | |
if ( v55.pa - 0x20000000 >= 0x10000000 ) | |
{ | |
if ( v55.pa - 402653184 > 0x600000 ) | |
{ | |
if ( v55.pa - 520093696 > 0x400000 ) | |
{ | |
if ( v55.pa - 0x10100000 > 0x1000000 ) | |
v36 = v55.pa - 0x1FF00000 > 0x80000 ? 0 : v55.pa; | |
else | |
v36 = v55.pa + 0xEB00000; | |
} | |
else | |
{ | |
v36 = v55.pa - 0x800000; | |
} | |
} | |
else | |
{ | |
v36 = v55.pa + 0x7000000; | |
} | |
} | |
else | |
{ | |
v36 = v55.pa - 0x40000000; | |
} | |
if ( v53.pa - 0x20000000 >= 0x10000000 ) | |
{ | |
if ( v53.pa - 0x18000000 > 0x600000 ) | |
{ | |
if ( v53.pa - 0x1F000000 > 0x400000 ) | |
{ | |
if ( v53.pa - 0x10100000 > 0x1000000 ) | |
{ | |
if ( v53.pa - 0x1FF00000 > 0x80000 ) | |
v35 = 0; | |
} | |
else | |
{ | |
v35 = v53.pa + 0xEB00000; | |
} | |
} | |
else | |
{ | |
v35 = v53.pa - 0x800000; | |
} | |
} | |
else | |
{ | |
v35 = v53.pa + 0x7000000; | |
} | |
v37 = v35; | |
} | |
else | |
{ | |
v37 = v53.pa + 0xC0000000; | |
} | |
memcpy((void *)v36, (const void *)v37, v17->size); | |
v38 = v53.pa; | |
v54 = v17->size; | |
ttblIterator.size = 0; // unmap | |
perms = 0; | |
v51 = KMEMUPDATE_NONE; | |
if ( v55.pa - 0x20000000 < 0x10000000 ) | |
goto LABEL_168; | |
pa = v55.pa >> 12 << 12; | |
v39 = pa; | |
v56 = v54 + v55.pa - pa; | |
if ( pa - 0x18000000 > 0x600000 ) | |
{ | |
if ( pa - 0x1F000000 > 0x400000 ) | |
{ | |
if ( pa - 0x10100000 > 0x1000000 ) | |
{ | |
if ( pa - 0x1FF00000 > 0x80000 ) | |
v39 = 0; | |
} | |
else | |
{ | |
v39 = (v55.pa >> 12 << 12) + 0xEB00000; | |
} | |
} | |
else | |
{ | |
v39 = pa - 0x800000; | |
} | |
} | |
else | |
{ | |
v39 = pa + 0x7000000; | |
} | |
result = KPageTable::Operate( | |
srcPgTbl, | |
v39, | |
(v56 + 4095) >> 12, | |
pa, | |
(KMemoryState)ttblIterator.size, | |
(KMemoryPermission)perms, | |
v51, | |
MEMOP_REGION_BASE); | |
if ( result >= 0 ) | |
{ | |
LABEL_168: | |
if ( v38 - 0x20000000 < 0x10000000 | |
|| ((ttblIterator.pa = v38 >> 12 << 12, | |
pa = v54 + v38 - ttblIterator.pa, | |
ttblIterator.pa - 0x18000000 > 0x600000) ? (ttblIterator.pa - 0x1F000000 > 0x400000 ? (ttblIterator.pa - 0x10100000 > 0x1000000 ? (ttblIterator.pa - 0x1FF00000 > 0x80000 ? (v40 = 0) : (v40 = ttblIterator.pa)) : (v40 = ttblIterator.pa + 0xEB00000)) : (v40 = ttblIterator.pa - 0x800000)) : (v40 = ttblIterator.pa + 0x7000000), | |
result = KPageTable::Operate( | |
this, | |
v40, | |
(pa + 4095) >> 12, | |
ttblIterator.pa, | |
(KMemoryState)ttblIterator.size, | |
(KMemoryPermission)perms, | |
v51, | |
0x300u), | |
result >= 0) ) | |
{ | |
result = 0; | |
} | |
} | |
if ( result < 0 ) | |
return result; | |
v41 = v17->size; | |
v14 += v41; | |
*(_DWORD *)(dstAddr + 12) += v41; | |
*(_DWORD *)(dstAddr + 16) -= v17->size; | |
v17->pa = v52.pa; | |
v27 = v52.size; | |
} | |
v17->size = v27; | |
} | |
v18 = v53.pa; | |
v19 = size - v14; | |
if ( v55.pa - 0x20000000 < 0x10000000 | |
|| ((v20 = v55.pa >> 12 << 12, v20 - 0x18000000 > 0x600000) ? (v20 - 0x1F000000 > 0x400000 ? (v20 - 0x10100000 > 0x1000000 ? (v20 - 0x1FF00000 > 0x80000 ? (v21 = 0) : (v21 = v55.pa >> 12 << 12)) : (v21 = v20 + 0xEB00000)) : (v21 = v20 - 0x800000)) : (v21 = v20 + 0x7000000), | |
result = KProcessPageTable::MapStaticOrIo(srcPgTbl, v21, (v55.pa - v20 + v19 + 4095) >> 12, 1, KMEMPERM_RW), | |
result >= 0) ) | |
{ | |
if ( v18 - 0x20000000 < 0x10000000 | |
|| ((v42 = v18 >> 12 << 12, v43 = v18 - v42 + v19, v42 - 402653184 > 0x600000) ? (v42 - 520093696 > 0x400000 ? (v42 - 269484032 > 0x1000000 ? (v42 - 535822336 > 0x80000 ? (v44 = 0) : (v44 = v42)) : (v44 = v42 + 246415360)) : (v44 = v42 - 0x800000)) : (v44 = v42 + 117440512), | |
result = KProcessPageTable::MapStaticOrIo(this, v44, (v43 + 4095) >> 12, 1, KMEMPERM_RW), | |
result >= 0) ) | |
{ | |
result = 0; | |
} | |
} | |
if ( result >= 0 ) | |
{ | |
v45 = v55.pa; | |
v46 = v53.pa; | |
if ( v55.pa - 0x20000000 >= 0x10000000 ) | |
{ | |
if ( v55.pa - 0x18000000 > 0x600000 ) | |
{ | |
if ( v55.pa - 0x1F000000 > 0x400000 ) | |
{ | |
if ( v55.pa - 0x10100000 > 0x1000000 ) | |
{ | |
if ( v55.pa - 0x1FF00000 > 0x80000 ) | |
v45 = 0; | |
} | |
else | |
{ | |
v45 = v55.pa + 246415360; | |
} | |
} | |
else | |
{ | |
v45 = v55.pa - 0x800000; | |
} | |
} | |
else | |
{ | |
v45 = v55.pa + 0x7000000; | |
} | |
} | |
else | |
{ | |
v45 = v55.pa - 0x40000000; | |
} | |
if ( v53.pa - 0x20000000 >= 0x10000000 ) | |
{ | |
if ( v53.pa - 0x18000000 > 0x600000 ) | |
{ | |
if ( v53.pa - 0x1F000000 > 0x400000 ) | |
{ | |
if ( v53.pa - 0x10100000 > 0x1000000 ) | |
{ | |
if ( v53.pa - 0x1FF00000 > 0x80000 ) | |
v46 = 0; | |
} | |
else | |
{ | |
v46 = v53.pa + 246415360; | |
} | |
} | |
else | |
{ | |
v46 = v53.pa - 0x800000; | |
} | |
} | |
else | |
{ | |
v46 = v53.pa + 0x7000000; | |
} | |
v47 = (const void *)v46; | |
} | |
else | |
{ | |
v47 = (const void *)(v53.pa + 0xC0000000); | |
} | |
memcpy((void *)v45, v47, size - v14); | |
result = KProcessPageTable::UnmapStaticOrIoByPa(this, v55.pa, srcPgTbl, v53.pa, size - v14); | |
if ( result >= 0 ) | |
return 0; | |
} | |
return result; | |
} | |
//----- (FFF1248C) -------------------------------------------------------- | |
void __fastcall KDebug::Intialize(KDebug *this, KProcess *process) | |
{ | |
this->signalingSyncEvent = 0; | |
this->process = process; // weak ref | |
process->debug = this; // weak ref | |
this->processAttached = 0; | |
KDebug::IntializeDebugThreads(this); | |
this->numExceptionEvents = 0; | |
this->signalingSyncEventThread = 0; | |
this->exceptionEventSignaled = 0; | |
this->excCtx = 0; | |
this->hasDebuggerBreak = 0; | |
this->isFirstExceptionBreak = 0; | |
this->hasAttachBreak = 0; | |
this->deferredExceptionContinue = 0; | |
this->deferredUserBreakContinue = 0; | |
this->numBlockingEvents = 0; | |
this->numAttachOrDetachEvents = 0; | |
this->debugFlags = 0xFFFE; // inhibit user exception handling, report everything | |
this->unk_24 = 0; | |
this->processExitedNormally = 0; | |
this->processTerminated = 0; | |
this->hasBreakSvc = 0; | |
this->outputStringAddr = 0; | |
this->outputStringSize = 0; | |
this->outputStringFlag = 0; | |
this->breakThread = 0; | |
this->userBreakThread = 0; | |
this->userDebuggerThread = 0; | |
this->userDebuggerCoreId = 0; | |
} | |
//----- (FFF12514) -------------------------------------------------------- | |
Result __fastcall KThread::AttachNewToDebug(KThread *this) | |
{ | |
KDebug *debug; // r5 | |
debug = this->owner->debug; | |
if ( !debug ) | |
return 0; | |
KDebug::AttachNewThread(debug, this); | |
if ( this->owner->mainThread == this ) // this is the main thread/first thread | |
// | |
// Try to run the debugger thread | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
KDebug::BuildOrderedListOfThreads(debug); | |
KDebug::RequestPause(debug, this); | |
if ( g_coreLocalRegions[this->coreId].clc.current.thread == this ) | |
KScheduler::TriggerSgi(current.clc.current.scheduler); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
this->debugThread->creatorThreadId = current.clc.current.thread->threadId; | |
return 0; | |
} | |
//----- (FFF125B0) -------------------------------------------------------- | |
Result __fastcall KThread::SignalExitToDebug(KThread *this) | |
{ | |
KDebug *owner; // r1 | |
bool v2; // zf | |
ExitThreadEventReason shallTerminate; // r2 | |
KDebug *process; // r0 | |
bool v5; // zf | |
owner = (KDebug *)this->owner; | |
v2 = owner == 0; | |
if ( owner ) | |
{ | |
owner = *(KDebug **)&owner->isFirstExceptionBreak;// ->debug | |
v2 = owner == 0; | |
} | |
if ( !v2 ) | |
{ | |
if ( owner->processExitedNormally ) | |
{ | |
shallTerminate = EXITTHREAD_EVENT_EXIT_PROCESS; | |
} | |
else if ( owner->processTerminated ) | |
{ | |
shallTerminate = EXITTHREAD_EVENT_TERMINATE_PROCESS; | |
} | |
else | |
{ | |
shallTerminate = this->shallTerminate; | |
} | |
process = (KDebug *)current.clc.current.process; | |
v5 = current.clc.current.process == 0; | |
if ( current.clc.current.process ) | |
{ | |
process = current.clc.current.process->debug; | |
v5 = process == 0; | |
} | |
if ( !v5 ) | |
KDebug::DispatchEvent(process, DBGEVENT_EXIT_THREAD, shallTerminate, 0); | |
} | |
return 0; | |
} | |
//----- (FFF12628) -------------------------------------------------------- | |
Result __fastcall KProcess::SetDebugExitedNormallyFlag(KProcess *this) | |
{ | |
KDebug *result; // r0 | |
result = this->debug; | |
if ( result ) | |
{ | |
result->processExitedNormally = 1; | |
return 0; | |
} | |
return (Result)result; | |
} | |
//----- (FFF12644) -------------------------------------------------------- | |
Result __fastcall KThread::SetDebugPauseOnInit(KThread *this) | |
{ | |
KDebug *debug; // r5 | |
KThread *volatile thread; // r4 | |
KDebugThread *debugThread; // r6 | |
bool v4; // zf | |
unsigned __int8 *p_dpcFlags; // r1 | |
unsigned __int8 v6; // r2 | |
debug = this->owner->debug; | |
if ( debug ) | |
{ | |
thread = current.clc.current.thread; | |
debugThread = current.clc.current.thread->debugThread; | |
v4 = debugThread == 0; | |
if ( debugThread ) | |
v4 = !debugThread->debugPauseRequested; | |
if ( !v4 ) | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
debugThread->debugPauseRequested = 0; | |
p_dpcFlags = &ADJ(thread->kernelStackTop)->dpcFlags; | |
do | |
v6 = __ldrex(p_dpcFlags); | |
while ( __strex(v6 & ~KDPCFLAG_DEBUG_PAUSE, p_dpcFlags) ); | |
KThread::SetDebugPauseState(thread, 1); | |
KDebug::RequestReschedulingForDebugger(debug, __mrc(15, 0, 0, 0, 5) & 3); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
} | |
return 0; | |
} | |
//----- (FFF126E8) -------------------------------------------------------- | |
Result __fastcall KThread::HandleDebugStopDpc(KThread *this) | |
{ | |
KDebug *debug; // r5 | |
KProcess *owner; // r1 | |
bool v3; // zf | |
KDebugThread *debugThread; // r0 | |
owner = this->owner; | |
v3 = owner == 0; | |
if ( owner ) | |
{ | |
debug = owner->debug; | |
v3 = debug == 0; | |
} | |
if ( !v3 ) | |
{ | |
debugThread = this->debugThread; | |
if ( debugThread->debugPauseRequested ) | |
{ | |
debugThread->debugPauseRequested = 0; | |
KThread::SetDebugPauseState(this, 1); | |
KDebug::RequestReschedulingForDebugger(debug, this->coreId); | |
} | |
} | |
return 0; | |
} | |
// FFF12730: variable 'debug' is possibly undefined | |
//----- (FFF1273C) -------------------------------------------------------- | |
Result __fastcall KProcess::SetDebugTerminatedFlag(KProcess *this) | |
{ | |
KDebug *result; // r0 | |
result = this->debug; | |
if ( result ) | |
{ | |
result->processTerminated = 1; | |
return 0; | |
} | |
return (Result)result; | |
} | |
//----- (FFF12758) -------------------------------------------------------- | |
Result __fastcall KDebug::BreakNoRo(KDebug *this, UserBreakType breakReason) | |
{ | |
KThread *volatile thread; // r5 | |
u32 kernelStackTop; // r0 | |
u32 v6; // r6 | |
bool v7; // zf | |
int v8; // r0 | |
int v9; // r0 | |
int v10; // r9 | |
thread = current.clc.current.thread; | |
kernelStackTop = (u32)ADJ(current.clc.current.thread->kernelStackTop)[1].svcAcl; | |
v6 = kernelStackTop - 0x110; | |
v7 = (*(_DWORD *)(kernelStackTop - 0xCC) & 0x20u) >> 5 == 0; | |
v8 = *(_DWORD *)(kernelStackTop - 0xD0); | |
if ( v7 ) | |
v9 = v8 - 4; // adjust PC | |
else | |
v9 = v8 - 2; | |
*(_DWORD *)(v6 + 0x40) = v9; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
this->hasBreakSvc = 1; | |
this->userBreakThread = thread; | |
thread->debugThread->isUserBreak = 1; | |
KThread::SetDebugPauseState(thread, 1); | |
KDebug::BreakCurrentProcess(this, thread); | |
v10 = KDebug::EmplaceAysncEventInfo(this, DBGEVENT_EXCEPTION, 1, breakReason, 6u, 0, 0, 0, 0); | |
if ( v10 >= 0 ) | |
{ | |
KSynchronizationObject::NotifyWaiters(this, 0); | |
KDebug::RequestReschedulingForDebugger(this, this->userDebuggerCoreId); | |
KDebug::RequestReschedulingForDebugger(this, __mrc(15, 0, 0, 0, 5) & 3); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
KSchedulerLock::Lock(&g_schedulerLock); | |
this->userBreakThread = 0; | |
thread->debugThread->isUserBreak = 0; | |
KDebug::UnbreakCurrentProcess(this); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
*(_DWORD *)(v6 + 0x24) = 1; // set lr = reload regs flag | |
} | |
else | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
return v10; | |
} | |
//----- (FFF12894) -------------------------------------------------------- | |
Result __fastcall KDebug::GetThreadContext( | |
KDebug *this, | |
ThreadContext *outThreadContext, | |
KThread *thread, | |
ThreadContextControlFlags flags) | |
{ | |
KThread *signalingSyncEventThread; // r5 | |
u32 kernelStackTop; // r12 | |
ExceptionDispatchContext *v6; // r12 | |
u32 v7; // r6 | |
u32 v8; // r7 | |
u32 v9; // r8 | |
u32 v10; // r9 | |
u32 v11; // r10 | |
u32 v12; // r11 | |
u32 v13; // lr | |
u32 v14; // r6 | |
u32 v15; // r7 | |
u32 v16; // r8 | |
u32 v17; // r9 | |
u32 *v18; // r12 | |
u32 cpsr; // r12 | |
ExceptionDispatchContext *v20; // r12 | |
u32 v21; // r6 | |
u32 v22; // r7 | |
u32 v23; // r8 | |
u32 v24; // r9 | |
u32 v25; // r10 | |
u32 v26; // r11 | |
u32 v27; // lr | |
u32 v28; // r6 | |
u32 v29; // r7 | |
u32 v30; // r8 | |
u32 v31; // r9 | |
KDebug *v32; // r7 | |
KThreadContext *context; // r0 | |
signalingSyncEventThread = this->signalingSyncEventThread; | |
kernelStackTop = (u32)ADJ(thread->kernelStackTop)[1].svcAcl; | |
if ( signalingSyncEventThread == thread | |
&& this->signalingSyncEvent | |
&& this->lastSyncDebugEventType == DBGEVENT_ATTACH_THREAD | |
&& !thread->debugThread->attached ) | |
{ | |
v18 = (u32 *)(kernelStackTop - 0x10C); // new thread, about to be actually attached | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_GPRS) != 0 ) | |
{ | |
outThreadContext->cpuRegisters.r[0] = *v18; | |
outThreadContext->cpuRegisters.r[1] = v18[1]; | |
outThreadContext->cpuRegisters.r[2] = v18[2]; | |
outThreadContext->cpuRegisters.r[3] = v18[3]; | |
outThreadContext->cpuRegisters.r[4] = v18[4]; | |
outThreadContext->cpuRegisters.r[5] = v18[5]; | |
outThreadContext->cpuRegisters.r[6] = v18[6]; | |
outThreadContext->cpuRegisters.r[7] = v18[7]; | |
outThreadContext->cpuRegisters.r[8] = v18[8]; | |
outThreadContext->cpuRegisters.r[9] = v18[9]; | |
outThreadContext->cpuRegisters.r[10] = v18[10]; | |
outThreadContext->cpuRegisters.r[11] = v18[11]; | |
outThreadContext->cpuRegisters.r[12] = v18[12]; | |
} | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_SPRS) == 0 ) | |
return KDebug::GetThreadVfpContext(this, outThreadContext, thread, flags); | |
outThreadContext->cpuRegisters.sp = v18[13]; | |
outThreadContext->cpuRegisters.lr = v18[14]; | |
outThreadContext->cpuRegisters.pc = v18[15]; | |
cpsr = v18[16]; | |
goto LABEL_21; | |
} | |
if ( this->excCtx && signalingSyncEventThread == thread )// exception | |
{ | |
if ( this->exceptionEventType ) // not undef instruction | |
{ | |
v6 = (ExceptionDispatchContext *)(kernelStackTop - 0x118); | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_GPRS) != 0 ) | |
{ | |
v7 = v6->r[1]; | |
v8 = v6->r[2]; | |
v9 = v6->r[3]; | |
v10 = v6->r[4]; | |
v11 = v6->r[5]; | |
v12 = v6->r[6]; | |
v13 = v6->r[7]; | |
outThreadContext->cpuRegisters.r[0] = v6->r[0]; | |
outThreadContext->cpuRegisters.r[1] = v7; | |
outThreadContext->cpuRegisters.r[2] = v8; | |
outThreadContext->cpuRegisters.r[3] = v9; | |
outThreadContext->cpuRegisters.r[4] = v10; | |
outThreadContext->cpuRegisters.r[5] = v11; | |
outThreadContext->cpuRegisters.r[6] = v12; | |
outThreadContext->cpuRegisters.r[7] = v13; | |
v14 = v6->r[9]; | |
v15 = v6->r[10]; | |
v16 = v6->r[11]; | |
v17 = v6->r[12]; | |
outThreadContext->cpuRegisters.r[8] = v6->r[8]; | |
outThreadContext->cpuRegisters.r[9] = v14; | |
outThreadContext->cpuRegisters.r[10] = v15; | |
outThreadContext->cpuRegisters.r[11] = v16; | |
outThreadContext->cpuRegisters.r[12] = v17; | |
} | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_SPRS) != 0 ) | |
{ | |
outThreadContext->cpuRegisters.sp = v6->sp; | |
outThreadContext->cpuRegisters.lr = v6->lr; | |
outThreadContext->cpuRegisters.pc = v6->pc; | |
outThreadContext->cpuRegisters.cpsr = v6->cpsr; | |
} | |
return KDebug::GetThreadVfpContext(this, outThreadContext, thread, flags); | |
} | |
v20 = (ExceptionDispatchContext *)(kernelStackTop - 0x118);// undefined instruction | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_GPRS) != 0 ) | |
{ | |
v21 = v20->r[1]; | |
v22 = v20->r[2]; | |
v23 = v20->r[3]; | |
v24 = v20->r[4]; | |
v25 = v20->r[5]; | |
v26 = v20->r[6]; | |
v27 = v20->r[7]; | |
outThreadContext->cpuRegisters.r[0] = v20->r[0]; | |
outThreadContext->cpuRegisters.r[1] = v21; | |
outThreadContext->cpuRegisters.r[2] = v22; | |
outThreadContext->cpuRegisters.r[3] = v23; | |
outThreadContext->cpuRegisters.r[4] = v24; | |
outThreadContext->cpuRegisters.r[5] = v25; | |
outThreadContext->cpuRegisters.r[6] = v26; | |
outThreadContext->cpuRegisters.r[7] = v27; | |
v28 = v20->r[9]; | |
v29 = v20->r[10]; | |
v30 = v20->r[11]; | |
v31 = v20->r[12]; | |
outThreadContext->cpuRegisters.r[8] = v20->r[8]; | |
outThreadContext->cpuRegisters.r[9] = v28; | |
outThreadContext->cpuRegisters.r[10] = v29; | |
outThreadContext->cpuRegisters.r[11] = v30; | |
outThreadContext->cpuRegisters.r[12] = v31; | |
} | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_SPRS) == 0 ) | |
return KDebug::GetThreadVfpContext(this, outThreadContext, thread, flags); | |
outThreadContext->cpuRegisters.sp = v20->sp; | |
outThreadContext->cpuRegisters.lr = v20->lr; | |
outThreadContext->cpuRegisters.pc = v20->pc; | |
cpsr = v20->cpsr; | |
LABEL_21: | |
outThreadContext->cpuRegisters.cpsr = cpsr; | |
return KDebug::GetThreadVfpContext(this, outThreadContext, thread, flags); | |
} | |
if ( !*(_BYTE *)(kernelStackTop - 0xB5) ) // not in svc (so in irq) | |
{ | |
v32 = this; | |
context = thread->context; | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_GPRS) != 0 ) | |
{ | |
outThreadContext->cpuRegisters.r[0] = *(_DWORD *)(kernelStackTop - 0xF0); | |
outThreadContext->cpuRegisters.r[1] = *(_DWORD *)(kernelStackTop - 0xEC); | |
outThreadContext->cpuRegisters.r[2] = *(_DWORD *)(kernelStackTop - 0xE8); | |
outThreadContext->cpuRegisters.r[3] = *(_DWORD *)(kernelStackTop - 0xE4); | |
outThreadContext->cpuRegisters.r[4] = *(_DWORD *)(kernelStackTop - 0x10C); | |
outThreadContext->cpuRegisters.r[5] = *(_DWORD *)(kernelStackTop - 0x108); | |
outThreadContext->cpuRegisters.r[6] = *(_DWORD *)(kernelStackTop - 0x104); | |
outThreadContext->cpuRegisters.r[7] = *(_DWORD *)(kernelStackTop - 0x100); | |
outThreadContext->cpuRegisters.r[8] = *(_DWORD *)(kernelStackTop - 0xFC); | |
outThreadContext->cpuRegisters.r[9] = *(_DWORD *)(kernelStackTop - 0xF8); | |
outThreadContext->cpuRegisters.r[10] = context->r10; | |
outThreadContext->cpuRegisters.r[11] = context->r11; | |
outThreadContext->cpuRegisters.r[12] = *(_DWORD *)(kernelStackTop - 0xE0); | |
} | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_SPRS) != 0 ) | |
{ | |
outThreadContext->cpuRegisters.sp = *(_DWORD *)(kernelStackTop - 216); | |
outThreadContext->cpuRegisters.lr = *(_DWORD *)(kernelStackTop - 212); | |
outThreadContext->cpuRegisters.pc = *(_DWORD *)(kernelStackTop - 208); | |
outThreadContext->cpuRegisters.cpsr = *(_DWORD *)(kernelStackTop - 204); | |
} | |
this = v32; | |
return KDebug::GetThreadVfpContext(this, outThreadContext, thread, flags); | |
} | |
return KDebug::GetThreadContextInSvc(this, outThreadContext, thread, flags); | |
} | |
//----- (FFF12B2C) -------------------------------------------------------- | |
Result __fastcall KDebug::SetThreadContext( | |
KDebug *this, | |
ThreadContext *threadContext, | |
KThread *thread, | |
ThreadContextControlFlags flags) | |
{ | |
KThread *signalingSyncEventThread; // r7 | |
u32 kernelStackTop; // r12 | |
ExceptionDispatchContext *v6; // r0 | |
u32 v7; // r7 | |
u32 v8; // r8 | |
u32 v9; // r9 | |
u32 v10; // r10 | |
u32 v11; // r11 | |
u32 v12; // r12 | |
u32 v13; // lr | |
u32 v14; // r7 | |
u32 v15; // r8 | |
u32 v16; // r9 | |
u32 v17; // r12 | |
_DWORD *v18; // r12 | |
u32 v19; // r7 | |
u32 v20; // r8 | |
u32 v21; // r9 | |
u32 v22; // r10 | |
u32 v23; // r11 | |
u32 v24; // r12 | |
u32 v25; // lr | |
u32 v26; // r7 | |
u32 v27; // r8 | |
u32 v28; // r9 | |
u32 v29; // r12 | |
u32 *v30; // r12 | |
u32 v31; // r8 | |
KThreadContext *context; // [sp+0h] [bp-30h] | |
KThread *v35; // [sp+4h] [bp-2Ch] | |
signalingSyncEventThread = this->signalingSyncEventThread; | |
kernelStackTop = (u32)ADJ(thread->kernelStackTop)[1].svcAcl; | |
if ( signalingSyncEventThread == thread | |
&& this->signalingSyncEvent | |
&& this->lastSyncDebugEventType == DBGEVENT_ATTACH_THREAD | |
&& !thread->debugThread->attached ) | |
{ | |
v18 = (_DWORD *)(kernelStackTop - 0x10C); // new thread, about to be actually attached | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_GPRS) != 0 ) | |
{ | |
*v18 = threadContext->cpuRegisters.r[0]; | |
v18[1] = threadContext->cpuRegisters.r[1]; | |
v18[2] = threadContext->cpuRegisters.r[2]; | |
v18[3] = threadContext->cpuRegisters.r[3]; | |
v18[4] = threadContext->cpuRegisters.r[4]; | |
v18[5] = threadContext->cpuRegisters.r[5]; | |
v18[6] = threadContext->cpuRegisters.r[6]; | |
v18[7] = threadContext->cpuRegisters.r[7]; | |
v18[8] = threadContext->cpuRegisters.r[8]; | |
v18[9] = threadContext->cpuRegisters.r[9]; | |
v18[10] = threadContext->cpuRegisters.r[10]; | |
v18[11] = threadContext->cpuRegisters.r[11]; | |
v18[12] = threadContext->cpuRegisters.r[12]; | |
} | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_SPRS) != 0 ) | |
{ | |
v18[13] = threadContext->cpuRegisters.sp; | |
v18[14] = threadContext->cpuRegisters.lr; | |
v18[15] = threadContext->cpuRegisters.pc; | |
v18[16] = v18[16] & 0x7F0FDFF | threadContext->cpuRegisters.cpsr & 0xF80F0200;// force usermode etc | |
} | |
} | |
else | |
{ | |
if ( this->excCtx && signalingSyncEventThread == thread )// exception (not svc/irq) | |
{ | |
if ( this->exceptionEventType ) // not undef | |
{ | |
v35 = thread; | |
v6 = (ExceptionDispatchContext *)(kernelStackTop - 0x118); | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_GPRS) != 0 ) | |
{ | |
v7 = threadContext->cpuRegisters.r[1]; | |
v8 = threadContext->cpuRegisters.r[2]; | |
v9 = threadContext->cpuRegisters.r[3]; | |
v10 = threadContext->cpuRegisters.r[4]; | |
v11 = threadContext->cpuRegisters.r[5]; | |
v12 = threadContext->cpuRegisters.r[6]; | |
v13 = threadContext->cpuRegisters.r[7]; | |
v6->r[0] = threadContext->cpuRegisters.r[0]; | |
v6->r[1] = v7; | |
v6->r[2] = v8; | |
v6->r[3] = v9; | |
v6->r[4] = v10; | |
v6->r[5] = v11; | |
v6->r[6] = v12; | |
v6->r[7] = v13; | |
v14 = threadContext->cpuRegisters.r[9]; | |
v15 = threadContext->cpuRegisters.r[10]; | |
v16 = threadContext->cpuRegisters.r[11]; | |
v17 = threadContext->cpuRegisters.r[12]; | |
v6->r[8] = threadContext->cpuRegisters.r[8]; | |
v6->r[9] = v14; | |
v6->r[10] = v15; | |
v6->r[11] = v16; | |
v6->r[12] = v17; | |
} | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_SPRS) == 0 ) | |
goto LABEL_20; | |
} | |
else | |
{ | |
v35 = thread; | |
v6 = (ExceptionDispatchContext *)(kernelStackTop - 280); | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_GPRS) != 0 ) | |
{ | |
v19 = threadContext->cpuRegisters.r[1]; | |
v20 = threadContext->cpuRegisters.r[2]; | |
v21 = threadContext->cpuRegisters.r[3]; | |
v22 = threadContext->cpuRegisters.r[4]; | |
v23 = threadContext->cpuRegisters.r[5]; | |
v24 = threadContext->cpuRegisters.r[6]; | |
v25 = threadContext->cpuRegisters.r[7]; | |
v6->r[0] = threadContext->cpuRegisters.r[0]; | |
v6->r[1] = v19; | |
v6->r[2] = v20; | |
v6->r[3] = v21; | |
v6->r[4] = v22; | |
v6->r[5] = v23; | |
v6->r[6] = v24; | |
v6->r[7] = v25; | |
v26 = threadContext->cpuRegisters.r[9]; | |
v27 = threadContext->cpuRegisters.r[10]; | |
v28 = threadContext->cpuRegisters.r[11]; | |
v29 = threadContext->cpuRegisters.r[12]; | |
v6->r[8] = threadContext->cpuRegisters.r[8]; | |
v6->r[9] = v26; | |
v6->r[10] = v27; | |
v6->r[11] = v28; | |
v6->r[12] = v29; | |
} | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_SPRS) == 0 ) | |
goto LABEL_20; | |
} | |
v6->sp = threadContext->cpuRegisters.sp; | |
v6->lr = threadContext->cpuRegisters.lr; | |
v6->pc = threadContext->cpuRegisters.pc; | |
v6->cpsr = v6->cpsr & 0x7F0FDFF | threadContext->cpuRegisters.cpsr & 0xF80F0200; | |
LABEL_20: | |
thread = v35; | |
return KDebug::SetThreadVfpContext(this, threadContext, thread, flags); | |
} | |
if ( *(_BYTE *)(kernelStackTop - 0xB5) ) // in svc | |
{ | |
v30 = (u32 *)(kernelStackTop - 0x110); | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_GPRS) != 0 ) | |
{ | |
*v30 = threadContext->cpuRegisters.r[0]; | |
v30[1] = threadContext->cpuRegisters.r[1]; | |
v30[2] = threadContext->cpuRegisters.r[2]; | |
v30[3] = threadContext->cpuRegisters.r[3]; | |
v30[4] = threadContext->cpuRegisters.r[4]; | |
v30[5] = threadContext->cpuRegisters.r[5]; | |
v30[6] = threadContext->cpuRegisters.r[6]; | |
v30[7] = threadContext->cpuRegisters.r[7]; | |
v30[10] = threadContext->cpuRegisters.r[8]; | |
v30[11] = threadContext->cpuRegisters.r[9]; | |
v30[12] = threadContext->cpuRegisters.r[10]; | |
v30[13] = threadContext->cpuRegisters.r[11]; | |
v31 = threadContext->cpuRegisters.r[12]; | |
v30[9] = 1; // set reload flag | |
v30[8] = v31; | |
} | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_SPRS) != 0 ) | |
{ | |
v30[14] = threadContext->cpuRegisters.sp; | |
v30[15] = threadContext->cpuRegisters.lr; | |
v30[16] = threadContext->cpuRegisters.pc; | |
v30[17] = v30[17] & 0x7F0FDFF | threadContext->cpuRegisters.cpsr & 0xF80F0200; | |
} | |
} | |
else // irq | |
{ | |
context = thread->context; | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_GPRS) != 0 ) | |
{ | |
*(_DWORD *)(kernelStackTop - 0xF0) = threadContext->cpuRegisters.r[0]; | |
*(_DWORD *)(kernelStackTop - 0xEC) = threadContext->cpuRegisters.r[1]; | |
*(_DWORD *)(kernelStackTop - 0xE8) = threadContext->cpuRegisters.r[2]; | |
*(_DWORD *)(kernelStackTop - 0xE4) = threadContext->cpuRegisters.r[3]; | |
*(_DWORD *)(kernelStackTop - 0x10C) = threadContext->cpuRegisters.r[4]; | |
*(_DWORD *)(kernelStackTop - 0x108) = threadContext->cpuRegisters.r[5]; | |
*(_DWORD *)(kernelStackTop - 0x104) = threadContext->cpuRegisters.r[6]; | |
*(_DWORD *)(kernelStackTop - 0x100) = threadContext->cpuRegisters.r[7]; | |
*(_DWORD *)(kernelStackTop - 0xFC) = threadContext->cpuRegisters.r[8]; | |
*(_DWORD *)(kernelStackTop - 0xF8) = threadContext->cpuRegisters.r[9]; | |
context->r10 = threadContext->cpuRegisters.r[10]; | |
context->r11 = threadContext->cpuRegisters.r[11]; | |
*(_DWORD *)(kernelStackTop - 0xE0) = threadContext->cpuRegisters.r[12]; | |
} | |
if ( (flags & THREADCONTEXT_CONTROL_CPU_SPRS) != 0 ) | |
{ | |
*(_DWORD *)(kernelStackTop - 0xD8) = threadContext->cpuRegisters.sp; | |
*(_DWORD *)(kernelStackTop - 0xD4) = threadContext->cpuRegisters.lr; | |
*(_DWORD *)(kernelStackTop - 0xD0) = threadContext->cpuRegisters.pc; | |
*(_DWORD *)(kernelStackTop - 0xCC) = *(_DWORD *)(kernelStackTop - 204) & 0x7F0FDFF | threadContext->cpuRegisters.cpsr & 0xF80F0200; | |
} | |
} | |
} | |
return KDebug::SetThreadVfpContext(this, threadContext, thread, flags); | |
} | |
//----- (FFF12EC4) -------------------------------------------------------- | |
Result __fastcall KDebug::Attach(KDebug *this, KProcess *process) | |
{ | |
KDebugThreadLinkedListNode *nd; // r1 | |
Result v5; // r0 | |
KDebugThreadLinkedListNode *node; // r7 | |
KThread *thread; // r8 | |
Result v8; // r0 | |
Result v9; // r9 | |
KProcess *v11; // r0 | |
KThread *mainThread; // r1 | |
ExceptionDispatchContext *excCtx; // r0 | |
bool v14; // zf | |
u32 baseUserVa; // r0 | |
Result v16; // r4 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
this->processAttached = 1; | |
KDebug::PauseProcess(this, 0); | |
for ( nd = this->debugThreads.link.next; nd != (KDebugThreadLinkedListNode *)&this->debugThreads.link; nd = nd->link.next ) | |
nd->debugThread->thread->debugThread->attached = 1; | |
v5 = KDebug::EmplaceAysncEventInfo(this, DBGEVENT_ATTACH_PROCESS, 1, (u32)process, 0, 0, 0, 0, 0); | |
if ( v5 < 0 ) | |
goto LABEL_17; | |
++this->numAttachOrDetachEvents; | |
for ( node = this->debugThreads.link.next; | |
node != (KDebugThreadLinkedListNode *)&this->debugThreads.link; | |
node = node->link.next ) | |
{ | |
thread = node->debugThread->thread; | |
v8 = KDebug::EmplaceAysncEventInfo(this, DBGEVENT_ATTACH_THREAD, 1, (u32)thread, 0, 0, 0, 0, 0); | |
if ( v8 < 0 ) | |
{ | |
v9 = v8; | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return v9; | |
} | |
++this->numAttachOrDetachEvents; | |
thread->debugThread->scheduledOut = 1; | |
} | |
v11 = this->process; | |
mainThread = v11->mainThread; | |
if ( mainThread ) | |
{ | |
excCtx = this->excCtx; // process has already been created | |
v14 = excCtx == 0; | |
if ( !excCtx ) | |
excCtx = (ExceptionDispatchContext *)&ADJ(mainThread->kernelStackTop)[1]; | |
baseUserVa = v14 ? excCtx[-3].r[8] : excCtx->pc;// get PC, either from the main thread or for the thread in exception | |
} | |
else | |
{ | |
baseUserVa = v11->codeSet->text.baseUserVa; | |
} | |
v5 = KDebug::EmplaceAysncEventInfo(this, DBGEVENT_EXCEPTION, 1, baseUserVa, 4u, 0, 0, 0, 0); | |
if ( v5 >= 0 ) | |
{ | |
this->isFirstExceptionBreak = 1; | |
this->hasAttachBreak = 1; | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
else | |
{ | |
LABEL_17: | |
v16 = v5; | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return v16; | |
} | |
} | |
//----- (FFF130A0) -------------------------------------------------------- | |
Result __fastcall KDebug::QueryProcessMemory(KDebug *this, MemoryInfo *outMemInfo, u32 *pgInfo, u32 addr) | |
{ | |
Result result; // r0 | |
u32 baseAddress; // r2 | |
u32 size; // r3 | |
u32 state_low; // r12 | |
KMemoryInfo v9; // [sp+0h] [bp-18h] BYREF | |
result = KPageTable::QueryInfo(&this->process->pgTable, &v9, pgInfo, addr); | |
baseAddress = v9.baseAddress; | |
size = v9.size; | |
state_low = LOBYTE(v9.state); | |
outMemInfo->perms = v9.perms & 3; | |
outMemInfo->state = state_low; | |
outMemInfo->baseAddress = baseAddress; | |
outMemInfo->size = size; | |
return result; | |
} | |
//----- (FFF130E4) -------------------------------------------------------- | |
KThread *__fastcall KThread::FindById(u32 id) | |
{ | |
unsigned int v2; // r2 | |
bool v3; // zf | |
unsigned int v4; // r3 | |
KThreadLinkedListNode *next; // r0 | |
KThread *thread; // r4 | |
v2 = __ldrex((unsigned int *)&g_threadAllocator.container.mutex); | |
v3 = v2 == 0; | |
if ( v2 ) | |
v4 = __strex(v2, (unsigned int *)&g_threadAllocator.container.mutex); | |
else | |
v4 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_threadAllocator.container.mutex); | |
if ( !v2 ) | |
v3 = v4 == 0; | |
if ( !v3 ) | |
KLightMutex::LockImpl(&g_threadAllocator.container.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
next = (KThreadLinkedListNode *)g_threadAllocator.container.list.link.next; | |
if ( (KAutoObjectLinkedListLink *)g_threadAllocator.container.list.link.next == &g_threadAllocator.container.list.link ) | |
{ | |
LABEL_14: | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_threadAllocator.container.mutex.lockingThread = 0; | |
if ( g_threadAllocator.container.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_threadAllocator.container.mutex); | |
return 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
thread = next->thread; | |
if ( thread->threadId == id ) | |
break; | |
next = next->link.next; | |
if ( next == (KThreadLinkedListNode *)&g_threadAllocator.container.list.link ) | |
goto LABEL_14; | |
} | |
KAutoObject::IncrementRefcount(next->thread); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_threadAllocator.container.mutex.lockingThread = 0; | |
if ( g_threadAllocator.container.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_threadAllocator.container.mutex); | |
return thread; | |
} | |
} | |
//----- (FFF1319C) -------------------------------------------------------- | |
void __fastcall KThread::SetSleepPriority(KThread *this, s32 priority) | |
{ | |
s32 basePriority; // r2 | |
this->dynamicPriority = priority; | |
basePriority = this->basePriority; | |
this->basePriority = priority; | |
this->priorityToRestoreAfterSleep = basePriority; | |
if ( priority != basePriority ) | |
KScheduler::AdjustThreadPriorityChanged(current.clc.current.scheduler, this, basePriority); | |
} | |
//----- (FFF131D0) -------------------------------------------------------- | |
void __fastcall KThread::RestorePriorityAfterSleep(KThread *this) | |
{ | |
s32 priorityToRestoreAfterSleep; // r1 | |
s32 dynamicPriority; // r2 | |
priorityToRestoreAfterSleep = this->priorityToRestoreAfterSleep; | |
this->priorityToRestoreAfterSleep = -1; | |
if ( priorityToRestoreAfterSleep == 64 ) | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
dynamicPriority = this->dynamicPriority; | |
this->basePriority = 64; | |
this->dynamicPriority = 64; | |
KScheduler::AdjustThreadPriorityChanged(current.clc.current.scheduler, this, dynamicPriority); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
else | |
{ | |
KThread::SetPriority(this, priorityToRestoreAfterSleep); | |
} | |
} | |
//----- (FFF13230) -------------------------------------------------------- | |
void __fastcall __noreturn KThread::Exit(KThread *this) | |
{ | |
u8 schedulingMask; // r2 | |
KMutex *p_link; // r0 | |
bool v4; // zf | |
KThread::SignalExitToDebug(this); | |
KHardwareTimer::CancelTask(&g_hardwareTimer, &this->KTimerTask);// inlined part 1, used in interrupt callbacks | |
KSchedulerLock::Lock(&g_schedulerLock); | |
KSchedulerLock::Lock(&g_schedulerLock); | |
schedulingMask = this->schedulingMask; | |
this->schedulingMask = schedulingMask & 0xF0 | KTHREADSCHEDSTAT_TERMINATED; | |
KScheduler::AdjustThreadScheduling(current.clc.current.scheduler, this, schedulingMask); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
KScheduler::RemoveTerminatingThread(current.clc.current.scheduler, this); | |
this->signaled = 1; | |
KSynchronizationObject::NotifyWaiters(this, 0); | |
while ( 1 ) | |
{ | |
p_link = (KMutex *)&ADJ(this->heldMutexListRootNode)->link; | |
v4 = p_link == 0; | |
if ( p_link ) | |
{ | |
p_link = (KMutex *)((char *)p_link - 20); | |
v4 = p_link == 0; | |
} | |
if ( v4 ) | |
{ | |
KThread::RemoveVfpUsageFromCurrentContext(this); | |
KWorkerTaskManager::AddTask(KWORKERTYPE_LOW_PRIO, &this->KWorkerTask); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
kernelpanic(); | |
} | |
KMutex::ForceUnlock(p_link, this); | |
} | |
} | |
//----- (FFF132FC) -------------------------------------------------------- | |
Result __fastcall KCodeSet::Initialize( | |
KCodeSet *this, | |
const CodeSetInfo *codeSetInfo, | |
KProcessPageTable *pgTable, | |
u32 textPtr, | |
u32 rodataPtr, | |
u32 dataPtr) | |
{ | |
KCodeSegment::Initialize(&this->text, &codeSetInfo->text, pgTable, textPtr); | |
KCodeSegment::Initialize(&this->rodata, &codeSetInfo->rodata, pgTable, rodataPtr); | |
KCodeSegment::Initialize(&this->data, &codeSetInfo->rwdata, pgTable, dataPtr); | |
KCodeSegment::EnsureCacheCoherencyForCode(&this->text); | |
this->numCodePages = codeSetInfo->text_size_total; | |
this->numConstPages = codeSetInfo->ro_size_total; | |
this->numDataPages = codeSetInfo->rw_size_total; | |
*(_QWORD *)this->processName = codeSetInfo->name; | |
this->processName[8] = 0; | |
this->unk1_from_codesetinfo = codeSetInfo->unk1; | |
this->titleId = codeSetInfo->program_id; | |
return 0; | |
} | |
//----- (FFF13390) -------------------------------------------------------- | |
Result __fastcall KCodeSet::CheckAndMap( | |
KCodeSet *this, | |
KProcessPageTable *pgTable, | |
u32 memoryRegion, | |
bool specialArrange) | |
{ | |
u32 baseUserVa; // r0 | |
Result v8; // r12 | |
Result result; // r0 | |
u32 v10; // r0 | |
Result v11; // r3 | |
u32 v12; // r0 | |
u32 rwStart; // r3 | |
KCodeSegment *__shifted(KCodeSet,0x30) p_data; // r4 | |
u32 v15; // t1 | |
u32 totalRwSize; // r1 | |
signed __int32 bssExtraNumPages; // r2 | |
bool v18; // zf | |
u32 v19; // r1 | |
if ( specialArrange ) | |
goto LABEL_16; | |
baseUserVa = this->text.baseUserVa; | |
v8 = 0xE0E01BF5; | |
if ( baseUserVa < 0x100000 || baseUserVa + (this->text.totalNumPages << 12) > 0x4000000 )// note that it doesn't check if the sections are contiguous, however | |
result = 0xE0E01BF5; | |
else | |
result = 0; | |
if ( result >= 0 ) | |
{ | |
v10 = this->rodata.baseUserVa; | |
if ( v10 < 0x100000 || v10 + (this->rodata.totalNumPages << 12) > 0x4000000 ) | |
v11 = 0xE0E01BF5; | |
else | |
v11 = 0; | |
result = v11; | |
if ( v11 >= 0 ) | |
{ | |
v12 = this->data.baseUserVa; | |
if ( v12 >= 0x100000 && v12 + (this->data.totalNumPages << 12) <= 0x4000000 ) | |
v8 = 0; | |
result = v8; | |
if ( v8 >= 0 ) | |
{ | |
LABEL_16: | |
result = KCodeSegment::Map(&this->text, pgTable, KMEMSTATE_PRIVATE_CODE, KMEMPERM_RX); | |
if ( result >= 0 ) | |
{ | |
result = KCodeSegment::Map(&this->rodata, pgTable, KMEMSTATE_PRIVATE_CODE, KMEMPERM_R); | |
if ( result >= 0 ) | |
{ | |
result = KCodeSegment::Map(&this->data, pgTable, KMEMSTATE_PRIVATE_DATA, KMEMPERM_RW); | |
if ( result >= 0 ) | |
{ | |
v15 = this->data.baseUserVa; | |
p_data = &this->data; | |
rwStart = v15; | |
totalRwSize = ADJ(p_data)->data.totalNumPages; | |
bssExtraNumPages = ADJ(p_data)->numDataPages - totalRwSize;// allocate extra pages for bss | |
v18 = ADJ(p_data)->numDataPages == totalRwSize; | |
if ( bssExtraNumPages < 0 ) | |
result = 136315904; | |
v19 = rwStart + (totalRwSize << 12); | |
if ( bssExtraNumPages >= 0 && !v18 ) | |
return KPageTable::Operate( | |
pgTable, | |
v19, | |
bssExtraNumPages, | |
0, | |
KMEMSTATE_PRIVATE_DATA, | |
KMEMPERM_KRW_RW, | |
KMEMUPDATE_NONE, | |
memoryRegion); | |
} | |
} | |
} | |
} | |
} | |
} | |
return result; | |
} | |
//----- (FFF134EC) -------------------------------------------------------- | |
bool __fastcall KProcess::IsTerminated(KProcess *this) | |
{ | |
return this->state == KPROCSTATE_TERMINATED; | |
} | |
//----- (FFF13500) -------------------------------------------------------- | |
Result __fastcall KProcess::DumpThreadIds(KProcess *this, s32 *outNumThreads, u32 *threadIdList, s32 threadIdListSize) | |
{ | |
unsigned int v8; // r2 | |
bool v9; // zf | |
unsigned int v10; // r3 | |
KThreadLinkedListNode *next; // r12 | |
s32 i; // r1 | |
KThread *thread; // r4 | |
v8 = __ldrex((unsigned int *)&g_threadAllocator.container.mutex); | |
v9 = v8 == 0; | |
if ( v8 ) | |
v10 = __strex(v8, (unsigned int *)&g_threadAllocator.container.mutex); | |
else | |
v10 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_threadAllocator.container.mutex); | |
if ( !v8 ) | |
v9 = v10 == 0; | |
if ( !v9 ) | |
KLightMutex::LockImpl(&g_threadAllocator.container.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
next = (KThreadLinkedListNode *)g_threadAllocator.container.list.link.next; | |
for ( i = 0; next != (KThreadLinkedListNode *)&g_threadAllocator.container.list.link; next = next->link.next ) | |
{ | |
thread = next->thread; | |
if ( thread->owner == this ) | |
{ | |
if ( i < threadIdListSize ) | |
threadIdList[i] = thread->threadId; | |
++i; | |
} | |
} | |
*outNumThreads = i; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_threadAllocator.container.mutex.lockingThread = 0; | |
if ( g_threadAllocator.container.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_threadAllocator.container.mutex); | |
return 0; | |
} | |
//----- (FFF135B8) -------------------------------------------------------- | |
bool __fastcall KProcess::TerminateImpl1(KProcess *this) | |
{ | |
unsigned __int8 *p_state; // r1 | |
unsigned __int8 v2; // r2 | |
bool v3; // zf | |
s32 i; // r4 | |
p_state = (unsigned __int8 *)&this->state; | |
do | |
{ | |
v2 = __ldrex(p_state); | |
v3 = v2 == KPROCSTATE_CREATED; | |
if ( v2 ) | |
v3 = v2 == KPROCSTATE_RUNNING; | |
if ( !v3 ) | |
{ | |
__clrex(); | |
return 0; | |
} | |
} | |
while ( __strex(KPROCSTATE_TERMINATING, p_state) ); | |
KProcess::ForceAllThreadsToTerminate(this, current.clc.current.thread); | |
for ( i = 0; i < 128; ++i ) | |
{ | |
if ( (this->boundIrqIds[(unsigned int)i >> 5] & (1 << (i & 0x1F))) != 0 ) | |
KInterruptManager::UnbindUserInterruptEvent(&g_interruptManager, i); | |
} | |
KHandleTable::Destroy(&this->handleTable); | |
return 1; | |
} | |
//----- (FFF13654) -------------------------------------------------------- | |
KProcess *__fastcall KProcess::OpenById(u32 pid) | |
{ | |
unsigned int v2; // r2 | |
bool v3; // zf | |
unsigned int v4; // r3 | |
KProcessLinkedListNode *next; // r0 | |
KProcess *process; // r4 | |
v2 = __ldrex((unsigned int *)&g_processAllocator.container.mutex); | |
v3 = v2 == 0; | |
if ( v2 ) | |
v4 = __strex(v2, (unsigned int *)&g_processAllocator.container.mutex); | |
else | |
v4 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_processAllocator.container.mutex); | |
if ( !v2 ) | |
v3 = v4 == 0; | |
if ( !v3 ) | |
KLightMutex::LockImpl(&g_processAllocator.container.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
next = (KProcessLinkedListNode *)g_processAllocator.container.list.link.next; | |
if ( (KAutoObjectLinkedListLink *)g_processAllocator.container.list.link.next == &g_processAllocator.container.list.link ) | |
{ | |
LABEL_15: | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_processAllocator.container.mutex.lockingThread = 0; | |
if ( g_processAllocator.container.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_processAllocator.container.mutex); | |
return 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
process = next->process; | |
if ( process->codeSet ) | |
{ | |
if ( process->pid == pid ) | |
break; | |
} | |
next = next->link.next; | |
if ( next == (KProcessLinkedListNode *)&g_processAllocator.container.list.link ) | |
goto LABEL_15; | |
} | |
KAutoObject::IncrementRefcount(next->process); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_processAllocator.container.mutex.lockingThread = 0; | |
if ( g_processAllocator.container.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_processAllocator.container.mutex); | |
return process; | |
} | |
} | |
//----- (FFF13718) -------------------------------------------------------- | |
bool __fastcall KProcess::ReserveResource(KProcess *this, ResourceLimitType type, s32 amount) | |
{ | |
KResourceLimit *reslimit; // r0 | |
BOOL v4; // r0 | |
reslimit = this->reslimit; | |
if ( !reslimit || (v4 = KResourceLimit::Reserve(reslimit, type, amount)) ) | |
LOBYTE(v4) = 1; | |
return v4; | |
} | |
//----- (FFF1373C) -------------------------------------------------------- | |
BOOL __fastcall KProcess::CheckThreadPriority(KProcess *this, s32 priority) | |
{ | |
KResourceLimit *reslimit; // r0 | |
reslimit = this->reslimit; | |
return !reslimit || KResourceLimit::GetLimitValue(reslimit, RESLIMIT_PRIORITY) <= priority; | |
} | |
//----- (FFF1376C) -------------------------------------------------------- | |
void __fastcall KProcess::IncrementThreadCount(KProcess *this) | |
{ | |
unsigned __int16 *p_threadCount; // r0 | |
unsigned __int16 v2; // r1 | |
p_threadCount = (unsigned __int16 *)&this->threadCount; | |
do | |
v2 = __ldrex(p_threadCount); | |
while ( __strex(v2 + 1, p_threadCount) ); | |
} | |
//----- (FFF137A8) -------------------------------------------------------- | |
Result __fastcall KProcess::AllocateTls(KProcess *this, u32 *outTlsUserAddr) | |
{ | |
KThreadLocalPageLinkedListNode *node; // r8 | |
KThreadLocalPage *tlsPage; // r4 | |
int v6; // r0 | |
u32 v7; // r4 | |
Result result; // r0 | |
KThreadLocalPage *v9; // r4 | |
int i; // r0 | |
u32 v11; // r10 | |
Result v12; // r10 | |
int v13; // r0 | |
u32 v14; // r9 | |
KThreadLocalPageLinkedList *p_threadLocalPages; // r8 | |
KThreadLocalPageLinkedListLink *p_link; // r5 | |
KLinkedListNode *v17; // r0 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
for ( node = this->threadLocalPages.link.next; | |
node != (KThreadLocalPageLinkedListNode *)&this->threadLocalPages.link; | |
node = node->link.next ) | |
{ | |
tlsPage = node->threadLocalPage; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
v6 = 0; | |
while ( !tlsPage->freeSlots[v6] ) | |
{ | |
if ( ++v6 >= 8 ) | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
goto LABEL_9; | |
} | |
} | |
tlsPage->freeSlots[v6] = 0; | |
++tlsPage->numThreads; | |
v7 = tlsPage->page + (v6 << 9); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
if ( v7 ) | |
{ | |
*outTlsUserAddr = v7; // ok, we found a free slot in an existing page | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
LABEL_9: | |
; | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
v9 = (KThreadLocalPage *)KSlabHeap::Allocate(&g_threadLocalPageSlabHeap); | |
if ( !v9 ) | |
return 0xD86007F3; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( !g_threadLocalPageTrackerInitialized ) | |
{ | |
memset(g_isThreadLocalPageVaFree, 0x7Eu, 1u); | |
g_threadLocalPageTrackerInitialized = 1; | |
} | |
for ( i = 0; i < 0x7E; ++i ) | |
{ | |
if ( g_isThreadLocalPageVaFree[i] ) | |
{ | |
g_isThreadLocalPageVaFree[i] = 0; | |
v11 = (i << 12) + 0x1FF82000; | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
goto LABEL_19; | |
} | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
v11 = 0; | |
LABEL_19: | |
v9->page = v11; | |
v9->parent = this; | |
v9->numThreads = 0; | |
result = KPageTable::Operate( | |
&this->pgTable, | |
v9->page, | |
1u, | |
0, | |
KMEMSTATE_LOCKED, | |
KMEMPERM_KRW_RW, | |
KMEMUPDATE_NONE, | |
MEMOP_REGION_BASE); | |
v12 = result; | |
if ( result >= 0 ) | |
{ | |
SetEightBytesTo1(v9->freeSlots, 1); | |
result = v12; | |
} | |
if ( result >= 0 ) | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
v13 = 0; | |
while ( !v9->freeSlots[v13] ) | |
{ | |
if ( ++v13 >= 8 ) | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0xD86007F3; | |
} | |
} | |
v9->freeSlots[v13] = 0; | |
++v9->numThreads; | |
v14 = v9->page + (v13 << 9); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
if ( !v14 ) | |
return 0xD86007F3; | |
*outTlsUserAddr = v14; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
p_threadLocalPages = &this->threadLocalPages; | |
p_link = &this->threadLocalPages.link; | |
v17 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v17 ) | |
{ | |
v17->link.next = 0; | |
v17->link.prev = 0; | |
v17->data = 0; | |
} | |
v17->data = v9; | |
KLinkedList::InsertAfter((KLinkedList *)p_threadLocalPages, (KLinkedListLink *)p_link, v17); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
return result; | |
} | |
// FFF13A00: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF13A7C) -------------------------------------------------------- | |
Result *__fastcall MakeResultCode(Result *result, u8 level, u8 summary, u8 module, u16 description) | |
{ | |
*result = (summary << 21) & 0x7E00000 | (level << 27) | (module << 10) | description & 0x3FF; | |
return result; | |
} | |
//----- (FFF13AAC) -------------------------------------------------------- | |
u32 __fastcall KHandleTable::GetTotalAllocatedSize(KHandleTable *this) | |
{ | |
unsigned int handleTableSize; // r0 | |
handleTableSize = this->handleTableSize; | |
if ( handleTableSize > 0x28 ) | |
return (8 * handleTableSize + 4095) >> 12 << 12; | |
else | |
return 0; | |
} | |
//----- (FFF13AD4) -------------------------------------------------------- | |
DmaState __fastcall KDmaChannel::GetDmaState(KDmaChannel *this) | |
{ | |
KLightMutex *p_mutex; // r0 | |
KLightMutex *v3; // r4 | |
unsigned int v4; // r2 | |
bool v5; // zf | |
unsigned int v6; // r3 | |
u32 cpc; // r7 | |
u32 lc0; // r8 | |
u32 lc1; // r9 | |
int state; // r3 | |
u32 numIter0; // r1 | |
u32 numIter1; // r2 | |
u32 firstWfpPa; // r0 | |
KLightMutex *v15; // r0 | |
bool v16; // cc | |
bool v17; // cc | |
int v18; // r1 | |
bool v19; // zf | |
int numWaiters; // r1 | |
p_mutex = &this->mutex; | |
v3 = p_mutex; | |
v4 = __ldrex((unsigned int *)p_mutex); | |
v5 = v4 == 0; | |
if ( v4 ) | |
v6 = __strex(v4, (unsigned int *)p_mutex); | |
else | |
v6 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)p_mutex); | |
if ( !v4 ) | |
v5 = v6 == 0; | |
if ( !v5 ) | |
KLightMutex::LockImpl(p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
cpc = KDmaController::GetChannelProgramCounter(this->channelId); | |
lc0 = KDmaController::GetLoopCounter(this->channelId, 0); | |
lc1 = KDmaController::GetLoopCounter(this->channelId, 1); | |
KDmaController::GetDestinationAddress(this->channelId);// unused, stubbed logging instr perhaps? | |
KDmaController::GetSourceAddress(this->channelId); | |
KDmaController::GetChannelStatus(this->channelId); | |
state = (unsigned __int8)this->state; | |
numIter0 = this->instFactory.lpNumIterations[0]; | |
numIter1 = this->instFactory.lpNumIterations[1]; | |
firstWfpPa = this->codeBufferPa + this->instFactory.firstWfpInstPtr - this->codeBuffer; | |
if ( state == KDMACHANSTATE_RESTARTED ) | |
{ | |
v15 = v3; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v3->lockingThread = 0; | |
if ( v3->numWaiters > 0 ) | |
goto LABEL_14; | |
return DMASTATE_RUNNING; | |
} | |
if ( state != 1 ) | |
{ | |
__mcr(15, 0, 0, 7, 10, 5); | |
v3->lockingThread = 0; | |
if ( v3->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v3); | |
return 4; | |
} | |
if ( !firstWfpPa ) | |
{ | |
v15 = v3; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v3->lockingThread = 0; | |
if ( v3->numWaiters <= 0 ) | |
return DMASTATE_RUNNING; | |
goto LABEL_14; | |
} | |
v16 = numIter0 != 0; | |
if ( this->instFactory.lpNumIterations[0] ) // check if we've done one loop iteration with wfp (erratum related?) | |
// | |
// "running" if not reached second wfp... (erratum-related?) | |
v16 = numIter0 > lc0; | |
if ( v16 ) | |
goto LABEL_23; | |
v17 = numIter1 != 0; | |
if ( this->instFactory.lpNumIterations[1] ) | |
v17 = numIter1 > lc1; | |
if ( v17 ) | |
{ | |
LABEL_23: | |
v15 = v3; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v3->lockingThread = 0; | |
if ( v3->numWaiters <= 0 ) | |
return DMASTATE_RUNNING; | |
goto LABEL_14; | |
} | |
if ( cpc < firstWfpPa ) | |
{ | |
__mcr(15, 0, 0, 7, 10, 5); | |
v3->lockingThread = 0; | |
if ( v3->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v3); | |
return DMASTATE_STARTING; | |
} | |
if ( cpc != firstWfpPa ) | |
{ | |
if ( cpc != firstWfpPa + 2 ) | |
{ | |
v15 = v3; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v3->lockingThread = 0; | |
if ( v3->numWaiters <= 0 ) | |
return DMASTATE_RUNNING; | |
goto LABEL_14; | |
} | |
v19 = !this->dmaConfig.dstIsDevice; // else | |
if ( this->dmaConfig.dstIsDevice ) | |
v19 = !this->dmaConfig.srcIsDevice; | |
v15 = v3; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v3->lockingThread = 0; | |
numWaiters = v3->numWaiters; | |
if ( !v19 ) | |
{ | |
if ( numWaiters <= 0 ) | |
return DMASTATE_WFP_SRC; | |
goto LABEL_37; | |
} | |
if ( numWaiters > 0 ) | |
LABEL_14: | |
KLightMutex::UnlockImpl(v15); | |
return DMASTATE_RUNNING; | |
} | |
v5 = !this->dmaConfig.dstIsDevice; | |
v15 = v3; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v3->lockingThread = 0; | |
v18 = v3->numWaiters; | |
if ( v5 ) | |
{ | |
if ( v18 <= 0 ) | |
return DMASTATE_WFP_SRC; | |
LABEL_37: | |
KLightMutex::UnlockImpl(v15); | |
return DMASTATE_WFP_SRC; | |
} | |
if ( v18 > 0 ) | |
KLightMutex::UnlockImpl(v3); | |
return DMASTATE_WFP_DST; | |
} | |
//----- (FFF13D0C) -------------------------------------------------------- | |
s64 __fastcall KMemoryBlockManger::GetTotalPrivateMemSize(KMemoryBlockManager *this) | |
{ | |
KMemoryBlockLinkedListNode *next; // r5 | |
KMemoryBlockLinkedListLink *p_link; // r4 | |
unsigned int v3; // r6 | |
KMemoryInfo v5; // [sp+0h] [bp-20h] BYREF | |
next = this->blocks.link.next; | |
p_link = &this->blocks.link; | |
v3 = 0; | |
while ( next != (KMemoryBlockLinkedListNode *)p_link ) | |
{ | |
KMemoryBlock::GetInfo(&v5, next->block); | |
next = next->link.next; | |
if ( (v5.state & KMEMSTATE_FLAG_PRIVATE) != 0 ) | |
v3 += v5.size; | |
} | |
return v3; | |
} | |
//----- (FFF13D60) -------------------------------------------------------- | |
s64 __fastcall KMemoryBlockManager::GetTotalCommittedMemory(KMemoryBlockManager *this) | |
{ | |
KMemoryBlockLinkedListNode *next; // r5 | |
KMemoryBlockLinkedListLink *p_link; // r4 | |
unsigned int i; // r6 | |
KMemoryInfo v5; // [sp+0h] [bp-20h] BYREF | |
next = this->blocks.link.next; | |
p_link = &this->blocks.link; | |
for ( i = 0; next != (KMemoryBlockLinkedListNode *)p_link; next = next->link.next ) | |
{ | |
KMemoryBlock::GetInfo(&v5, next->block); // if (baseAddr >= 0x20000000) | |
if ( v5.baseAddress - 0x1C000000 >= 0x4000000 && (v5.state & KMEMSTATE_FLAG_PRIVATE) != 0 ) | |
i += v5.size; | |
} | |
return i; | |
} | |
//----- (FFF13DC4) -------------------------------------------------------- | |
s64 __fastcall KMemoryBlockManger::GetTotalPrivateOrSharedMemSize(KMemoryBlockManager *this) | |
{ | |
KMemoryBlockLinkedListNode *next; // r5 | |
KMemoryBlockLinkedListLink *p_link; // r4 | |
unsigned int v3; // r6 | |
KMemoryInfo v5; // [sp+0h] [bp-20h] BYREF | |
next = this->blocks.link.next; | |
p_link = &this->blocks.link; | |
v3 = 0; | |
while ( next != (KMemoryBlockLinkedListNode *)p_link ) | |
{ | |
KMemoryBlock::GetInfo(&v5, next->block); | |
next = next->link.next; | |
if ( (v5.state & KMEMSTATE_FLAGS_PRIVATE_OR_SHARED) != 0 ) | |
v3 += v5.size; | |
} | |
return v3; | |
} | |
//----- (FFF13E18) -------------------------------------------------------- | |
u32 __fastcall KThread::GetProcessId(KThread *this) | |
{ | |
KProcess *owner; // r0 | |
owner = this->owner; | |
if ( owner ) | |
return owner->pid; | |
else | |
return -1; | |
} | |
//----- (FFF13E2C) -------------------------------------------------------- | |
// positive sp value has been detected, the output may be wrong! | |
void __fastcall __noreturn KThread::UserThreadStarter(int a1, int a2, int a3, int a4, int a5) | |
{ | |
SignalNewThreadEntry(); | |
__asm { RFEFD SP! } | |
} | |
// FFF13E3C: positive sp value 3C has been found | |
// FFF13E3C: control flows out of bounds to FFF13E40 | |
//----- (FFF13E44) -------------------------------------------------------- | |
// positive sp value has been detected, the output may be wrong! | |
int KThread::SupervisorThreadStarter() | |
{ | |
int (__fastcall *v5)(); // [sp-4h] [bp-4h] | |
__asm { CPSIE AIF } | |
return v5(); | |
} | |
// FFF13E48: positive sp value 8 has been found | |
// FFF13E4C: variable 'v5' is possibly undefined | |
// FFF13E44: using guessed type int KThread::SupervisorThreadStarter(); | |
//----- (FFF13E50) -------------------------------------------------------- | |
void __fastcall CallFuncWithStackAllocImpl(void *args, u32 stackAllocSize, FuncWithStackAlloc func) | |
{ | |
int v3; // [sp+8h] [bp+0h] BYREF | |
func(args, &v3); | |
} | |
//----- (FFF13E70) -------------------------------------------------------- | |
void __fastcall memset(void *a1, size_t a2, unsigned __int8 a3) | |
{ | |
memset(a1, a3 | (a3 << 8) | ((a3 | (a3 << 8)) << 16), a2); | |
} | |
//----- (FFF13E80) -------------------------------------------------------- | |
char *__fastcall strncpy(char *dstStr, const char *srcStr, u32 count) | |
{ | |
bool v3; // zf | |
char *v4; // r4 | |
bool v5; // cc | |
int v6; // r3 | |
int v7; // t1 | |
int v8; // t1 | |
v3 = ((unsigned __int8)dstStr & 3) == 0; | |
v4 = dstStr; | |
if ( ((unsigned __int8)dstStr & 3) == 0 ) | |
v3 = ((unsigned __int8)srcStr & 3) == 0; | |
if ( v3 ) | |
{ | |
while ( 1 ) | |
{ | |
v5 = (int)count < 4; | |
count -= 4; | |
if ( v5 ) | |
goto LABEL_9; | |
v7 = *(_DWORD *)srcStr; | |
srcStr += 4; | |
v6 = v7; | |
if ( ((v7 - 16843009) & ~v7 & 0x80808080) != 0 ) | |
break; | |
*(_DWORD *)dstStr = v6; | |
dstStr += 4; | |
} | |
srcStr -= 4; | |
LABEL_9: | |
count += 4; | |
} | |
while ( 1 ) | |
{ | |
v5 = (int)count-- < 1; | |
if ( v5 ) | |
break; | |
v8 = *(unsigned __int8 *)srcStr++; | |
*dstStr++ = v8; | |
if ( !v8 ) | |
{ | |
memset(dstStr, 0, count); | |
return v4; | |
} | |
} | |
return v4; | |
} | |
//----- (FFF13F1C) -------------------------------------------------------- | |
void __fastcall KResourceLimit::Initialize(KResourceLimit *this) | |
{ | |
KCpuTimeLimit *p_timeLimit; // r4 | |
this->limitValues[0] = 0; | |
this->limitValues[1] = 0; | |
this->limitValues[2] = 0; | |
this->limitValues[3] = 0; | |
this->limitValues[4] = 0; | |
this->limitValues[5] = 0; | |
this->limitValues[6] = 0; | |
this->limitValues[7] = 0; | |
this->limitValues[8] = 0; | |
this->limitValues[9] = 0; | |
this->currentValues[0] = 0; | |
this->currentValues[1] = 0; | |
this->currentValues[2] = 0; | |
this->currentValues[3] = 0; | |
this->currentValues[4] = 0; | |
this->currentValues[5] = 0; | |
this->currentValues[6] = 0; | |
this->currentValues[7] = 0; | |
this->currentValues[8] = 0; | |
this->currentValues[9] = 0; | |
p_timeLimit = &this->timeLimit; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
p_timeLimit->next = g_cpuTimeLimitListHead; | |
g_cpuTimeLimitListHead = p_timeLimit; | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
//----- (FFF13FAC) -------------------------------------------------------- | |
Result __fastcall KCapability::Initialize(KCapability *this, u32 *caps, s32 numCaps, KProcessPageTable *pgTable) | |
{ | |
s32 i; // r4 | |
u32 cap; // r1 | |
int j; // r0 | |
u32 v10; // r2 | |
u32 v11; // r9 | |
u32 v12; // r0 | |
KMemoryPermission perms; // r11 | |
int v14; // r10 | |
bool v15; // zf | |
unsigned int v16; // r0 | |
Result result; // r0 | |
int v18; // r3 | |
unsigned int v19; // r3 | |
int v20; // r0 | |
unsigned int v21; // r12 | |
int v22; // r1 | |
KProcessPageTable *v23; // r9 | |
u32 v24; // r10 | |
bool v25; // zf | |
unsigned int v26; // r0 | |
KMemoryInfo userPerms; // [sp+0h] [bp-60h] BYREF | |
u32 size; // [sp+10h] [bp-50h] BYREF | |
u32 addr; // [sp+14h] [bp-4Ch] | |
KMemoryInfo outMemoryInfo; // [sp+18h] [bp-48h] BYREF | |
u32 pageInfo[4]; // [sp+28h] [bp-38h] BYREF | |
this->svcAcl[0] = 0; | |
this->svcAcl[1] = 0; | |
this->svcAcl[2] = 0; | |
this->svcAcl[3] = 0; | |
this->irqAcl[0] = 0; | |
this->irqAcl[1] = 0; | |
this->irqAcl[2] = 0; | |
this->irqAcl[3] = 0; | |
this->handleTableSize = 0; | |
pageInfo[1] = (u32)this; | |
pageInfo[2] = (u32)caps; | |
pageInfo[3] = numCaps; | |
for ( i = 0; i < numCaps; ++i ) | |
{ | |
cap = caps[i]; | |
if ( (cap & 0xF0000000) == 0xE0000000 ) | |
{ // irq caps | |
for ( j = 0; j < 4; ++j ) | |
{ | |
v18 = (cap >> (7 * j)) & 0x7F; | |
if ( v18 != 127 ) | |
{ | |
if ( ((this->irqAcl[((cap >> (7 * j)) & 0x7F) >> 5] >> ((cap >> (7 * j)) & 0x1F)) & 1) != 0 ) | |
{ | |
result = 0xD900140E; | |
goto LABEL_33; | |
} | |
if ( (unsigned int)v18 <= 0xE ) | |
v18 += 127; | |
if ( v18 >= 128 ) | |
{ | |
result = 0xD9001412; | |
goto LABEL_33; | |
} | |
this->irqAcl[v18 / 32] |= 1 << (v18 % 32); | |
} | |
} | |
result = 0; | |
LABEL_33: | |
if ( result < 0 ) | |
return result; | |
} | |
else if ( (cap & 0xF8000000) == 0xF0000000 ) | |
{ // svc ACL | |
v19 = cap & 0xFFFFFF; | |
v20 = 0; | |
v21 = 3 * ((cap & 0x7000000) >> 24); | |
do | |
{ | |
if ( ((v19 >> v20) & 1) != 0 ) | |
{ | |
v22 = v20 + 8 * v21; | |
if ( v22 < 128 ) | |
*((_BYTE *)this->svcAcl + v22 / 8) |= 1 << (v22 % 8); | |
} | |
++v20; | |
} | |
while ( v20 < 24 ); | |
} | |
else if ( (cap & 0xFF000000) == 0xFE000000 ) | |
{ | |
this->handleTableSize = cap & 0x3FF; | |
} | |
else if ( cap >> 23 == 510 ) | |
{ | |
this->kernelFlags = cap; | |
} | |
else if ( cap >> 21 == 0x7FC ) | |
{ // static pages or io page | |
if ( i + 1 >= numCaps ) | |
return 0xD9001412; | |
v10 = caps[i + 1]; | |
if ( v10 >> 21 != 0x7FC ) | |
return 0xD9001412; | |
v11 = cap << 12; | |
userPerms.size = (u32)pgTable; | |
userPerms.perms = ((v10 << 12) - (cap << 12) + 4095) >> 12; | |
if ( (cap & 0x100000) != 0 ) | |
v12 = 1; | |
else | |
v12 = 3; | |
userPerms.baseAddress = v12; | |
userPerms.state = ((v10 >> 20) & 1) == 0; | |
addr = cap << 12; | |
perms = userPerms.perms; | |
v14 = 0; | |
size = userPerms.size; | |
if ( userPerms.perms <= KMEMPERM_NONE ) | |
{ | |
LABEL_42: | |
result = KProcessPageTable::MapStaticOrIoExheaderRange( | |
(KProcessPageTable *)userPerms.size, | |
addr, | |
userPerms.perms, | |
userPerms.state, | |
(KMemoryPermission)userPerms.baseAddress);// overlapping stack args, urgh | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
v16 = (unsigned int)KPageTable::QueryInfo((KPageTable *)size, &outMemoryInfo, pageInfo, v11 + (v14 << 12)) >> 31; | |
v15 = v16 == 0; | |
if ( !v16 ) | |
v15 = outMemoryInfo.state == MEMSTATE_FREE;// check if all the pages we want are free | |
if ( !v15 ) | |
break; | |
if ( ++v14 >= perms ) | |
goto LABEL_42; | |
} | |
result = -654306288; | |
} | |
if ( result < 0 ) | |
return result; | |
++i; | |
} | |
else if ( cap >> 20 == 0xFFE ) | |
{ // io pages | |
v23 = pgTable; | |
v24 = cap << 12; | |
v26 = (unsigned int)KPageTable::QueryInfo(pgTable, &userPerms, &size, cap << 12) >> 31; | |
v25 = v26 == 0; | |
if ( !v26 ) | |
v25 = userPerms.state == MEMSTATE_FREE; | |
if ( v25 ) | |
result = KProcessPageTable::MapStaticOrIoExheaderRange(v23, v24, 1u, 1, KMEMPERM_RW); | |
else | |
result = 0; | |
if ( result < 0 ) | |
return result; | |
} | |
else if ( (cap & 0xFE000000) == 0xFC000000 ) | |
{ | |
this->intendedKernelVersion = cap; | |
if ( (unsigned __int16)cap > 0x239u ) // current kernel ver: 2.55 | |
return 0xD9001413; | |
} | |
else if ( cap != 0xFFFFFFFF ) | |
{ | |
return 0xD9001412; | |
} | |
} | |
return 0; | |
} | |
//----- (FFF142F8) -------------------------------------------------------- | |
void __fastcall KPort::Initialize(KPort *this, s32 maxSessionCount) | |
{ | |
s16 v2; // r5 | |
unsigned __int16 *p_currentSessionCount; // r3 | |
v2 = maxSessionCount; | |
KAutoObject::IncrementRefcount(this); | |
KAutoObject::Initialize(&this->server); | |
KAutoObject::Initialize(&this->client); | |
this->server.parent = this; | |
p_currentSessionCount = (unsigned __int16 *)&this->client.currentSessionCount; | |
do | |
__ldrex(p_currentSessionCount); | |
while ( __strex(0, p_currentSessionCount) ); | |
this->client.parent = this; | |
this->client.maxSessionCount = v2; | |
} | |
//----- (FFF14368) -------------------------------------------------------- | |
Result __fastcall KDmaManager::ValidateUserParameters( | |
u32 dstAddr, | |
u32 srcAddr, | |
u32 size, | |
DmaConfig *dmaCfg, | |
KProcess *process, | |
KProcess *srcProcess) | |
{ | |
Result result; // r0 | |
unsigned int channelId; // r1 | |
int endianSwapSize; // r2 | |
bool v11; // zf | |
bool v12; // zf | |
u8 flags; // r0 | |
int dstIsDevice; // r7 | |
int useDstCfg; // r5 | |
bool srcIsDevice; // r8 | |
BOOL useSrcCfg; // r6 | |
int transferSize; // r10 | |
int v19; // r11 | |
bool v20; // zf | |
s32 v21; // r0 | |
KDmaBufferSize v22; // [sp+0h] [bp-78h] BYREF | |
KDmaAddress dmaAddr; // [sp+Ch] [bp-6Ch] BYREF | |
s32 alignment; // [sp+24h] [bp-54h] | |
int outMinAlgnSrc[4]; // [sp+2Ch] [bp-4Ch] BYREF | |
int outMinAlgnDst[2]; // [sp+3Ch] [bp-3Ch] BYREF | |
u32 dstAddra; // [sp+44h] [bp-34h] | |
u32 v28; // [sp+48h] [bp-30h] | |
u32 v29; // [sp+4Ch] [bp-2Ch] | |
DmaConfig *v30; // [sp+50h] [bp-28h] | |
if ( !size ) | |
return -656406548; | |
dstAddra = dstAddr; | |
v28 = srcAddr; | |
v29 = size; | |
v30 = dmaCfg; | |
channelId = dmaCfg->channelId; | |
result = -656406552; | |
if ( channelId == -1 || channelId < 8 ) | |
{ | |
endianSwapSize = dmaCfg->endianSwapSize; | |
v11 = endianSwapSize == 0; | |
if ( dmaCfg->endianSwapSize ) | |
v11 = endianSwapSize == 2; | |
if ( v11 ) | |
goto LABEL_58; | |
v12 = endianSwapSize == 4; | |
if ( endianSwapSize != 4 ) | |
v12 = endianSwapSize == 8; | |
if ( v12 ) | |
{ | |
LABEL_58: | |
flags = dmaCfg->flags; // usage of subcfg is forced for devices | |
outMinAlgnDst[0] = 1; | |
outMinAlgnSrc[0] = 1; | |
dstIsDevice = (unsigned __int8)(flags & DMACFGFLAG_DST_IS_DEVICE) >> 1; | |
useDstCfg = (flags & (unsigned __int8)DMACFGFLAG_USE_DST_CONFIG) != 0 ? 1 : (unsigned __int8)(flags & DMACFGFLAG_DST_IS_DEVICE) >> 1; | |
srcIsDevice = flags & DMACFGFLAG_SRC_IS_DEVICE; | |
useSrcCfg = (flags & DMACFGFLAG_USE_SRC_CONFIG) != 0 || flags & DMACFGFLAG_SRC_IS_DEVICE; | |
if ( !useDstCfg | |
|| (result = KDmaManager::CheckDeviceConfig( | |
outMinAlgnDst, | |
&dmaCfg->dstCfg, | |
endianSwapSize, | |
(unsigned __int8)(flags & DMACFGFLAG_DST_IS_DEVICE) >> 1), | |
result >= 0) ) | |
{ | |
if ( !useSrcCfg | |
|| (result = KDmaManager::CheckDeviceConfig( | |
outMinAlgnSrc, | |
&dmaCfg->srcCfg, | |
dmaCfg->endianSwapSize, | |
srcIsDevice), | |
result >= 0) ) | |
{ | |
if ( (useDstCfg & useSrcCfg) != 0 ) | |
{ | |
transferSize = dmaCfg->dstCfg.transferSize; | |
v19 = dmaCfg->srcCfg.transferSize; | |
v20 = transferSize == 0; | |
if ( dmaCfg->dstCfg.transferSize ) | |
v20 = v19 == 0; | |
if ( !v20 && v19 % transferSize && transferSize % v19 ) | |
return 0xD90007EE; | |
} | |
v21 = outMinAlgnDst[0]; | |
if ( outMinAlgnDst[0] <= outMinAlgnSrc[0] ) | |
v21 = outMinAlgnSrc[0]; | |
alignment = v21; | |
KDmaAddress::KDmaAddress(&dmaAddr); | |
memset(&v22, 0, sizeof(v22)); | |
KDmaAddress::Initialize(&dmaAddr, dstAddra, dstIsDevice, process); | |
if ( useSrcCfg ) | |
KDmaBufferSize::ComputeFromConfig(&v22, size, &dmaCfg->srcCfg); | |
else | |
KDmaBufferSize::operator=(&v22, size); | |
if ( !KDmaAddress::CheckBufferRangeValid(&dmaAddr, v22.minOffset, v22.maxOffset) ) | |
return 0xE0E01BF5; | |
if ( KDmaAddress::CheckVirtualAddressBlockUsable(&dmaAddr, v22.minOffset, v22.maxOffset, 1) ) | |
{ | |
if ( !KDmaAddress::CheckAlignment(&dmaAddr, alignment) ) | |
return 0xD8E007F1; | |
if ( useSrcCfg | |
&& (dmaCfg->srcCfg.burstSize > dmaCfg->srcCfg.burstStride | |
|| dmaCfg->srcCfg.transferSize > dmaCfg->srcCfg.transferStride) | |
&& !KDmaAddress::CheckPhysicalMemContiguous(&dmaAddr, v22.minOffset, v22.maxOffset) ) | |
{ | |
return 0xE0E01BF5; | |
} | |
KDmaAddress::Initialize(&dmaAddr, v28, srcIsDevice, srcProcess); | |
if ( useDstCfg ) | |
KDmaBufferSize::ComputeFromConfig(&v22, size, &dmaCfg->dstCfg); | |
else | |
KDmaBufferSize::operator=(&v22, size); | |
if ( !KDmaAddress::CheckBufferRangeValid(&dmaAddr, v22.minOffset, v22.maxOffset) ) | |
return 0xE0E01BF5; | |
if ( KDmaAddress::CheckVirtualAddressBlockUsable(&dmaAddr, v22.minOffset, v22.maxOffset, 0) ) | |
{ | |
if ( KDmaAddress::CheckAlignment(&dmaAddr, alignment) ) | |
{ | |
if ( !useDstCfg | |
|| dmaCfg->dstCfg.burstSize <= dmaCfg->dstCfg.burstStride | |
&& dmaCfg->dstCfg.transferSize <= dmaCfg->dstCfg.transferStride | |
|| KDmaAddress::CheckPhysicalMemContiguous(&dmaAddr, v22.minOffset, v22.maxOffset) ) | |
{ | |
return 0; | |
} | |
return 0xE0E01BF5; | |
} | |
return 0xD8E007F1; | |
} | |
} | |
return 0xD9000402; | |
} | |
} | |
} | |
} | |
return result; | |
} | |
// FFF14368: using guessed type s32 outMinAlgnDst; | |
// FFF14368: using guessed type s32 outMinAlgnSrc; | |
//----- (FFF146B8) -------------------------------------------------------- | |
Result __fastcall KDmaManager::InitializeChannel( | |
KDmaManager *this, | |
Handle *outDmaObjectHandle, | |
KDmaChannel **outDmaChannel, | |
s8 channelId, | |
u8 cfgFlags) | |
{ | |
int v8; // r0 | |
int selectedChannelId; // r5 | |
int v10; // r0 | |
KDmaObject *v12; // r0 | |
KDmaObject *dmaObject; // r4 | |
KDmaObject *v14; // r0 | |
int v15; // r6 | |
KHandleTable *p_handleTable; // r6 | |
int v17; // r6 | |
KDmaChannel *v18; // r5 | |
KTypeObj v19; // [sp+0h] [bp-40h] BYREF | |
int channelId_; // [sp+18h] [bp-28h] | |
channelId_ = channelId; | |
if ( (cfgFlags & DMACFGFLAG_WAIT_AVAILABLE) != 0 ) | |
{ | |
while ( 1 ) | |
{ | |
v8 = KDmaManager::TryLockChannel(this, channelId); | |
if ( v8 >= 0 ) | |
break; | |
KThread::Sleep(current.clc.current.thread, 100000LL);// 100 us | |
} | |
selectedChannelId = v8; | |
} | |
else | |
{ | |
v10 = KDmaManager::TryLockChannel(this, channelId); | |
selectedChannelId = v10; | |
if ( v10 < 0 ) | |
return 0xD04007F0; | |
} | |
while ( 1 ) | |
{ | |
v12 = (KDmaObject *)KSlabHeap::Allocate(&g_dmaObjectAllocator.slabHeap); | |
dmaObject = v12; | |
if ( v12 ) | |
{ | |
v14 = (KDmaObject *)KSynchronizationObject::KSynchronizationObject(v12); | |
v14->__vftable = &KDmaObject::vt; | |
v14->channelId = -1; | |
v14->signaled = 1; | |
KAutoObject::Initialize(dmaObject); | |
} | |
if ( dmaObject ) | |
break; | |
KThread::Sleep(current.clc.current.thread, 100000LL); | |
} | |
dmaObject->channelId = selectedChannelId; | |
v15 = KObjectAllocator::Register(&g_dmaObjectAllocator, dmaObject); | |
if ( v15 >= 0 ) | |
{ | |
p_handleTable = ¤t.clc.current.process->handleTable; | |
dmaObject->GetTypeObj(&v19, dmaObject); | |
v17 = KHandleTable::Add(p_handleTable, outDmaObjectHandle, dmaObject, v19.typeId); | |
if ( v17 >= 0 ) | |
{ | |
v18 = &g_dmaChannels[selectedChannelId]; | |
KDmaChannel::Initialize(v18, &this->KDmaChannelEventHandler, dmaObject); | |
*outDmaChannel = v18; | |
} | |
else | |
{ | |
dmaObject->DecrementRefcount(dmaObject); | |
} | |
return v17; | |
} | |
else | |
{ | |
dmaObject->DecrementRefcount(dmaObject); | |
return v15; | |
} | |
} | |
// FFF14768: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF14894) -------------------------------------------------------- | |
void __fastcall KSlabHeap::Initialize(KSlabHeap *this, u32 elementSize, void *addr, u32 totalSize) | |
{ | |
KSlabHeap *first; // r4 | |
signed __int32 i; // r2 | |
this->first = (KSlabHeap *)addr; | |
this->totalSize = totalSize; | |
this->elementSize = elementSize; | |
do | |
__ldrex((unsigned int *)this); | |
while ( __strex((unsigned int)addr, (unsigned int *)this) ); | |
first = this->first; | |
for ( i = 0; (int)(totalSize / elementSize) > i; first = (KSlabHeap *)((char *)first + elementSize) ) | |
{ | |
++i; | |
first->currentHead = (KSlabHeapNode *)((char *)first + elementSize); | |
} | |
*(KSlabHeapNode **)((char *)&first->currentHead - elementSize) = 0; | |
} | |
//----- (FFF148F8) -------------------------------------------------------- | |
void __fastcall KPageHeap::Initialize(KPageHeap *this, u32 regionStart, u32 regionSize) | |
{ | |
u32 *p_regionStart; // r0 | |
u32 *key; // r5 | |
int v6; // r6 | |
int i; // r4 | |
u32 v8; // r0 | |
KPageHeapBlock *firstBlock; // r0 | |
u32 v10; // r3 | |
p_regionStart = &this->regionStart; | |
*p_regionStart = regionStart; | |
p_regionStart[1] = regionSize; | |
memset((void *)regionStart, 0, regionSize); | |
this->key[0] = 0; | |
this->key[1] = 0; | |
this->key[2] = 0; | |
key = this->key; | |
v6 = 0; | |
this->key[3] = 0; | |
do | |
{ | |
for ( i = 0; i < 4; ++i ) | |
{ | |
v8 = key[i] - KHardwareTimer::GetSystemTick(&g_hardwareTimer); | |
key[i] = v8; | |
key[i] = v8 ^ (__ROR4__(v8, 7) - __ROR4__(key[((_BYTE)v6 + (_BYTE)i) & 3], 17)); | |
} | |
++v6; | |
} | |
while ( v6 < 64 ); | |
firstBlock = (KPageHeapBlock *)this->regionStart; | |
this->link.next = firstBlock; // next is first | |
if ( firstBlock ) | |
{ | |
v10 = this->regionSize; | |
firstBlock->link.next = 0; | |
firstBlock->numPages = v10 >> 12; | |
firstBlock->link.prev = 0; | |
firstBlock->current = firstBlock; | |
firstBlock->nonce = 0; | |
firstBlock->mac = 0; | |
KPageHeap::UpdateBlockMac(this, this->link.next); | |
if ( this->link.next->numPages != this->regionSize >> 12 ) | |
kernelpanic(); | |
} | |
this->link.prev = this->link.next; | |
} | |
//----- (FFF149E4) -------------------------------------------------------- | |
void *__fastcall _aeabi_vec_ctor_nocookie_nodtor( | |
void *user_array, | |
void *(__fastcall *constructor)(void *), | |
u32 element_size, | |
u32 element_count) | |
{ | |
char *i; // r5 | |
if ( constructor ) | |
{ | |
for ( i = (char *)user_array; element_count-- != 0; i += element_size ) | |
constructor(i); | |
} | |
return user_array; | |
} | |
//----- (FFF14A08) -------------------------------------------------------- | |
s32 __fastcall Ncch::ConvertSize(s32 size, u32 unused, s32 unitSize) | |
{ | |
if ( unitSize - 32 >= 0 ) | |
return 0; | |
else | |
return size << unitSize; | |
} | |
//----- (FFF14A30) -------------------------------------------------------- | |
// positive sp value has been detected, the output may be wrong! | |
void __fastcall __noreturn DispatchExceptionWithRegdump(int a1, int a2, int a3, int a4, int a5) | |
{ | |
int v5; // lr | |
_DWORD v10[15]; // [sp-8h] [bp-48h] BYREF | |
int v11; // [sp+34h] [bp-Ch] | |
void (__fastcall *v12)(_DWORD *); // [sp+38h] [bp-8h] BYREF | |
v10[14] = &v12; | |
v11 = v5; | |
v10[0] = a1; | |
v10[1] = a2; | |
v10[2] = a3; | |
v10[3] = a4; | |
__asm { CPSIE AF } | |
v12(v10); | |
__asm | |
{ | |
CPSID AIF | |
RFEFD SP! | |
} | |
} | |
// FFF14A5C: positive sp value 8 has been found | |
// FFF14A30: variable 'v5' is possibly undefined | |
//----- (FFF14A60) -------------------------------------------------------- | |
Result __fastcall DispatchDebugEventFromException(DebugEventType type, u32 param1, u32 param2) | |
{ | |
KProcess *volatile *var; // r0 | |
KProcess *volatile process; // r2 | |
bool v8; // r5 | |
Result result; // r0 | |
bool v10; // zf | |
var = ¤t.clc.current.process; | |
process = current.clc.current.process; | |
if ( type == DBGEVENT_SCHEDULE_IN ) | |
{ | |
result = g_scheduledOut[__mrc(15, 0, 0, 0, 5) & 3]; | |
if ( !result ) | |
return result; | |
var = (KProcess *volatile *)(__mrc(15, 0, 0, 0, 5) & 3); | |
v8 = 0; | |
goto LABEL_6; | |
} | |
if ( type == DBGEVENT_SCHEDULE_OUT ) | |
{ | |
var = (KProcess *volatile *)(__mrc(15, 0, 0, 0, 5) & 3); | |
v8 = 1; | |
LABEL_6: | |
g_scheduledOut[(_DWORD)var] = v8; | |
} | |
v10 = process == 0; | |
if ( process ) | |
{ | |
var = (KProcess *volatile *)process->debug; | |
v10 = var == 0; | |
} | |
if ( v10 ) | |
return 0; | |
else | |
return KDebug::DispatchEvent((KDebug *)var, type, param1, param2); | |
} | |
// FFF2F058: using guessed type bool g_scheduledOut[8]; | |
//----- (FFF14AF0) -------------------------------------------------------- | |
Result __fastcall KDebug::CheckMemoryAddressRange(KDebug *this, u32 addr, u32 size, bool isDstProcess, bool write) | |
{ | |
u32 endAddr; // r0 | |
KProcess *process; // r5 | |
int v8; // r2 | |
u32 v10; // r1 | |
KProcess *volatile *p_process; // r0 | |
KThread *v12; // r0 | |
unsigned __int8 *p_dpcFlags; // r2 | |
unsigned __int8 v14; // r3 | |
int v15; // r1 | |
_DWORD regions[2]; // [sp+0h] [bp-48h] | |
u32 addrs[2]; // [sp+8h] [bp-40h] | |
KMemoryInfo outMemoryInfo; // [sp+10h] [bp-38h] BYREF | |
int pageInfo[10]; // [sp+20h] [bp-28h] BYREF | |
endAddr = addr + size - 1; | |
process = (KProcess *)isDstProcess; | |
v8 = 0; | |
addrs[1] = endAddr; | |
addrs[0] = addr; | |
do | |
{ | |
regions[v8] = 0; | |
v10 = addrs[v8]; | |
if ( v10 < 0x100000 ) | |
return 0xD86007F3; | |
if ( v10 >= 0x4000000 ) | |
{ | |
if ( v10 >= 0x40000000 ) | |
return 0xD86007F3; | |
regions[v8] = 2; | |
} | |
else | |
{ | |
regions[v8] = 1; | |
} | |
++v8; | |
} | |
while ( v8 < 2 ); | |
p_process = (KProcess *volatile *)regions[0]; | |
if ( regions[0] == regions[1] ) // if we cross regions, return an error | |
{ | |
if ( isDstProcess ) | |
process = this->process; | |
else | |
p_process = ¤t.clc.current.process; | |
if ( !isDstProcess ) | |
process = *p_process; | |
v12 = (KThread *)__ldrex((unsigned int *)&process->pgTable);// avoid deadlock on the processpagetable? | |
// | |
// but uh, we don't lock the mutex here, do we? | |
if ( v12 && v12->owner == this->process ) | |
{ | |
v12->debugThread->debugPauseRequested = 1; | |
p_dpcFlags = &ADJ(v12->kernelStackTop)->dpcFlags; | |
do | |
v14 = __ldrex(p_dpcFlags); | |
while ( __strex(v14 | KDPCFLAG_DEBUG_PAUSE, p_dpcFlags) );// that one is bugged | |
KThread::SetDebugPauseState(v12, 0); // unpause the thread for now but pause it later | |
// ... without signaling any event? | |
} | |
v15 = KPageTable::QueryInfo(&process->pgTable, &outMemoryInfo, (u32 *)pageInfo, addr); | |
if ( v15 < 0 ) | |
return v15; | |
if ( write ) | |
{ | |
if ( (outMemoryInfo.perms & KMEMPERM_KW_W) != 0 ) | |
return 0; | |
} | |
else if ( (outMemoryInfo.perms & KMEMPERM_KR_R) != 0 ) | |
{ | |
return 0; // but uh, kernel read perms are set everywhere? | |
} | |
} | |
return 0xD86007F3; | |
} | |
// FFF14AF0: using guessed type u32 pageInfo[10]; | |
//----- (FFF14C48) -------------------------------------------------------- | |
void __fastcall KProcess::TerminateCurrentProcess(KProcess *this) | |
{ | |
KThread *thread; // r6 | |
thread = current.clc.current.thread; | |
KProcess::SetDebugExitedNormallyFlag(this); | |
if ( KProcess::TerminateImpl1(this) ) | |
{ | |
KWorkerTaskManager::AddTask(KWORKERTYPE_HIGH_PRIO, &this->KWorkerTask); | |
KThread::Exit(thread); | |
} | |
KThread::SetPriority(thread, 63); | |
while ( 1 ) | |
KScheduler::YieldCurrentThread(current.clc.current.scheduler); | |
} | |
//----- (FFF14CAC) -------------------------------------------------------- | |
u32 __fastcall KPageHeap::GetTotalNumPages(KPageHeap *this) | |
{ | |
KPageHeapBlock *next; // r4 | |
u32 v3; // r5 | |
bool v4; // zf | |
u32 numPages; // r0 | |
next = this->link.next; | |
v3 = 0; | |
v4 = this->link.next == 0; | |
if ( this->link.next ) | |
v4 = this->link.prev == 0; | |
if ( !v4 ) | |
{ | |
do | |
{ | |
KPageHeap::ValidateBlock(this, next); | |
numPages = next->numPages; | |
next = next->link.next; | |
v3 += numPages; | |
} | |
while ( next ); | |
} | |
return v3; | |
} | |
//----- (FFF14CF0) -------------------------------------------------------- | |
bool __fastcall CallFuncWithStackAlloc(FuncWithStackAlloc func, void *args, u32 stackAllocSize) | |
{ | |
u32 v5; // r1 | |
bool v6; // cc | |
bool result; // r0 | |
v5 = (stackAllocSize + 7) & ~7u; | |
v6 = v5 > 0x400; | |
if ( v5 <= 0x400 ) | |
v6 = stackAllocSize > v5; | |
if ( !v6 || (result = 0, !v6) ) | |
{ | |
CallFuncWithStackAllocImpl(args, v5, func); | |
return 1; | |
} | |
return result; | |
} | |
//----- (FFF14D28) -------------------------------------------------------- | |
KThread *__fastcall KHandleTable::ConvertToThreadAllowPseudoHandle(KHandleTable *this, Handle handle) | |
{ | |
KThread *thread; // r4 | |
KAutoObject *v4; // r0 | |
KThread *v5; // r4 | |
KThread *v6; // r5 | |
u8 typeId; // r7 | |
KTypeObj v8; // [sp+0h] [bp-28h] BYREF | |
KTypeObj v9; // [sp+8h] [bp-20h] BYREF | |
if ( handle == CUR_THREAD_HANDLE ) | |
{ | |
thread = current.clc.current.thread; | |
KAutoObject::IncrementRefcount(current.clc.current.thread); | |
return thread; | |
} | |
else | |
{ | |
v4 = KHandleTable::ConvertToAutoObject(this, handle); | |
v5 = (KThread *)v4; | |
v6 = 0; | |
if ( v4 ) | |
{ | |
v4->GetTypeObj(&v8, v4); | |
typeId = v8.typeId; | |
v5->GetTypeObj(&v9, v5); | |
if ( (typeId | 0x8D) == v9.typeId ) | |
return v5; | |
else | |
v5->DecrementRefcount(v5); | |
} | |
return v6; | |
} | |
} | |
//----- (FFF14DE8) -------------------------------------------------------- | |
KDebug *__fastcall KHandleTable::ConvertCurProcHandleToDebug(Handle debugHandle) | |
{ | |
KAutoObject *v1; // r0 | |
KDebug *v2; // r4 | |
KDebug *v3; // r5 | |
unsigned __int8 v4; // r7 | |
_BYTE v6[8]; // [sp+0h] [bp-28h] BYREF | |
char v7[32]; // [sp+8h] [bp-20h] BYREF | |
v1 = KHandleTable::ConvertToAutoObject(¤t.clc.current.process->handleTable, debugHandle); | |
v2 = (KDebug *)v1; | |
v3 = 0; | |
if ( v1 ) | |
{ | |
v1->GetTypeObj((KTypeObj *)v6, v1); | |
v4 = v6[4]; | |
v2->GetTypeObj((KTypeObj *)v7, v2); | |
if ( (v4 | 0x4D) == (unsigned __int8)v7[4] ) | |
return v2; | |
else | |
v2->DecrementRefcount(v2); | |
} | |
return v3; | |
} | |
//----- (FFF14E88) -------------------------------------------------------- | |
BOOL __fastcall KDebug::IsProcessTerminated(KDebug *this) | |
{ | |
KProcess *process; // r0 | |
BOOL result; // r0 | |
process = this->process; | |
if ( !process ) | |
return 1; | |
result = KProcess::IsTerminated(process); | |
if ( result ) | |
return 1; | |
return result; | |
} | |
//----- (FFF14EAC) -------------------------------------------------------- | |
KResourceLimit *__fastcall KHandleTable::ConvertToResourceLimit(KHandleTable *this, Handle reslimitHandle) | |
{ | |
KResourceLimit *result; // r0 | |
KResourceLimit *v3; // r4 | |
u8 typeId; // r6 | |
int v5; // r1 | |
KResourceLimit *v6; // r5 | |
KTypeObj v7; // [sp+0h] [bp-20h] BYREF | |
KTypeObj v8; // [sp+8h] [bp-18h] BYREF | |
result = (KResourceLimit *)KHandleTable::ConvertToAutoObject(this, reslimitHandle); | |
v3 = result; | |
if ( result ) | |
{ | |
result->GetTypeObj(&v7, result); | |
typeId = v7.typeId; | |
v3->GetTypeObj(&v8, v3); | |
v5 = typeId | 0xC8; | |
if ( v5 == v8.typeId ) | |
v6 = v3; | |
else | |
v6 = 0; | |
if ( v5 != v8.typeId ) | |
v3->DecrementRefcount(v3); | |
return v6; | |
} | |
return result; | |
} | |
//----- (FFF14F34) -------------------------------------------------------- | |
KProcess *__fastcall KHandleTable::ConvertToProcessAllowPseudoHandle(KHandleTable *this, Handle handle) | |
{ | |
KProcess *process; // r4 | |
KAutoObject *v4; // r0 | |
KProcess *v5; // r4 | |
KProcess *v6; // r5 | |
u8 typeId; // r7 | |
KTypeObj v8; // [sp+0h] [bp-28h] BYREF | |
KTypeObj v9; // [sp+8h] [bp-20h] BYREF | |
if ( handle == CUR_PROCESS_HANDLE ) | |
{ | |
process = current.clc.current.process; | |
KAutoObject::IncrementRefcount(current.clc.current.process); | |
return process; | |
} | |
else | |
{ | |
v4 = KHandleTable::ConvertToAutoObject(this, handle); | |
v5 = (KProcess *)v4; | |
v6 = 0; | |
if ( v4 ) | |
{ | |
v4->GetTypeObj(&v8, v4); | |
typeId = v8.typeId; | |
v5->GetTypeObj(&v9, v5); | |
if ( (typeId | 0xC5) == v9.typeId ) | |
return v5; | |
else | |
v5->DecrementRefcount(v5); | |
} | |
return v6; | |
} | |
} | |
//----- (FFF14FF4) -------------------------------------------------------- | |
void __fastcall KDebug::UnpauseAllThreads(KDebug *this, BOOL checkBreak) | |
{ | |
KThreadLinkedListNode *nd; // r4 | |
KThread *thread; // r0 | |
KThreadLinkedListNode *v6; // r10 | |
KLinkedListLink *v7; // r0 | |
KLinkedListLink *v8; // r8 | |
KDebugThreadLinkedListNode *i; // r4 | |
KThread *v10; // r0 | |
u8 schedulingMask; // r1 | |
bool v12; // zf | |
KDebugThread *debugThread; // r1 | |
unsigned __int8 *p_dpcFlags; // r1 | |
unsigned __int8 v15; // r2 | |
KThreadLinkedListNode *nd2; // [sp+0h] [bp-28h] BYREF | |
for ( nd = this->orderedThreadListForBreak.link.next; | |
nd != (KThreadLinkedListNode *)&this->orderedThreadListForBreak.link; | |
nd = nd->link.next ) | |
{ | |
thread = nd->thread; | |
if ( !checkBreak || (thread->schedulingMask & (unsigned __int8)KTHREADSCHEDSTAT_DEBUG_PAUSE_FLAG) != 0 ) | |
{ | |
thread->debugThread->debugPauseRequested = 0; | |
KThread::SetDebugPauseState(thread, 0); | |
} | |
} | |
nd2 = this->orderedThreadListForBreak.link.next; | |
if ( nd2 != (KThreadLinkedListNode *)&this->orderedThreadListForBreak.link ) | |
{ | |
do | |
{ | |
v6 = nd2; | |
KLinkedList::EraseNode((KLinkedList *)&this->orderedThreadListForBreak, (KLinkedListLink **)&nd2); | |
v8 = v7; // ???? | |
KSlabHeap::Free(&g_linkedListNodeSlabHeap, v6); | |
nd2 = (KThreadLinkedListNode *)v8; | |
} | |
while ( v8 != (KLinkedListLink *)&this->orderedThreadListForBreak.link ); | |
} | |
for ( i = this->debugThreads.link.next; i != (KDebugThreadLinkedListNode *)&this->debugThreads.link; i = i->link.next ) | |
{ | |
v10 = i->debugThread->thread; | |
schedulingMask = v10->schedulingMask; | |
if ( (schedulingMask & 0xF) != KTHREADSCHEDSTAT_TERMINATED ) | |
{ | |
v12 = (unsigned __int8)(schedulingMask & KTHREADSCHEDSTAT_DEBUG_PAUSE_FLAG) == 0; | |
debugThread = v10->debugThread; | |
if ( v12 ) | |
{ | |
if ( debugThread->debugPauseRequested ) | |
{ | |
p_dpcFlags = &ADJ(v10->kernelStackTop)->dpcFlags; | |
do | |
v15 = __ldrex(p_dpcFlags); | |
while ( __strex(v15 & ~KDPCFLAG_DEBUG_PAUSE, p_dpcFlags) );// again, dpc handler is bugged | |
v10->debugThread->debugPauseRequested = 0; | |
} | |
} | |
else | |
{ | |
debugThread->debugPauseRequested = 0; | |
KThread::SetDebugPauseState(v10, 0); | |
} | |
} | |
} | |
} | |
// FFF1507C: variable 'v7' is possibly undefined | |
//----- (FFF15138) -------------------------------------------------------- | |
u32 __fastcall KProcess::GetLinearAddrRangeBase(KProcess *this) | |
{ | |
if ( (this->capability.kernelFlags & 0xF00) == MEMOP_REGION_BASE || this->capability.intendedKernelVersion >= 0x22Cu )// | |
// base sysmodules, or 8.x+ titles. | |
// | |
// This code is common to O3DS/N3DS | |
return 0x30000000; | |
else | |
return 0x14000000; | |
} | |
//----- (FFF15160) -------------------------------------------------------- | |
u32 __fastcall KObjectAllocator::CountObjectsOwnedByProcess(KObjectAllocator *this, KProcess *process) | |
{ | |
KLightMutex *p_mutex; // r0 | |
KLightMutex *v5; // r6 | |
unsigned int v6; // r2 | |
bool v7; // zf | |
unsigned int v8; // r3 | |
KProcessLinkedListNode *next; // r4 | |
u32 v10; // r7 | |
KProcess *owner; // r0 | |
p_mutex = &this->container.mutex; | |
v5 = p_mutex; | |
v6 = __ldrex((unsigned int *)p_mutex); | |
v7 = v6 == 0; | |
if ( v6 ) | |
v8 = __strex(v6, (unsigned int *)p_mutex); | |
else | |
v8 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)p_mutex); | |
if ( !v6 ) | |
v7 = v8 == 0; | |
if ( !v7 ) | |
KLightMutex::LockImpl(p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
next = (KProcessLinkedListNode *)this->container.list.link.next; | |
v10 = 0; | |
while ( next != (KProcessLinkedListNode *)&this->container.list.link ) | |
{ | |
owner = next->process->GetOwnerProcess(next->process); | |
next = next->link.next; | |
if ( owner == process ) | |
++v10; | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
v5->lockingThread = 0; | |
if ( v5->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v5); | |
return v10; | |
} | |
//----- (FFF15200) -------------------------------------------------------- | |
void __fastcall KThread::PrepareToRun(KThread *this) | |
{ | |
if ( this->owner ) | |
KThread::SetDebugPauseOnInit(this); | |
KSchedulerLock::Lock(&g_schedulerLock); | |
KScheduler::InitializeNewThread(current.clc.current.scheduler, this); | |
if ( this->owner ) | |
KThread::AttachNewToDebug(this); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
//----- (FFF15254) -------------------------------------------------------- | |
Result __fastcall KThread::Initialize( | |
KThread *this, | |
u32 ep, | |
u32 arg, | |
u32 kernelStackTop, | |
u32 stackTop, | |
s32 priority, | |
s32 idealCore, | |
KProcess *parentProcess, | |
KThreadType threadType) | |
{ | |
KResourceLimit *reslimit; // r11 | |
bool v12; // zf | |
bool *p_shallTerminate; // r0 | |
int v14; // r0 | |
bool v15; // zf | |
bool v16; // cc | |
u32 v17; // r0 | |
bool v18; // zf | |
unsigned int v19; // r2 | |
bool v20; // zf | |
KThreadLinkedListNode *next; // r0 | |
KThread *thread; // r2 | |
KProcess *owner; // r3 | |
bool v24; // zf | |
s32 LimitValue; // r0 | |
int v27; // r0 | |
bool v28; // zf | |
bool v29; // zf | |
u32 v30; // r0 | |
KThreadStackParametersPtr v31; // r0 | |
KProcess *v32; // r1 | |
KThreadStackParameters *v33; // r0 | |
u32 v34; // r2 | |
u32 v35; // r3 | |
u32 v36; // r12 | |
unsigned __int8 *p_dpcFlags; // r1 | |
u32 v38; // r1 | |
u32 arg_; // [sp+14h] [bp-2Ch] | |
arg_ = arg; | |
this->tlsUserAddr = 0; | |
v12 = threadType == KTHREAD_TYPE_IDLE; | |
if ( threadType ) | |
v12 = threadType == KTHREAD_TYPE_KERNEL; | |
if ( !v12 ) | |
v12 = threadType == KTHREAD_TYPE_KERNEL_CRITICAL; | |
if ( v12 ) | |
goto LABEL_25; | |
if ( threadType != KTHREAD_TYPE_USER ) | |
kernelpanic(); | |
if ( idealCore == -2 ) | |
{ | |
this->idealProcessor = parentProcess->idealProcessor; | |
this->affinityMask = parentProcess->affinityMask; | |
goto LABEL_8; | |
} | |
if ( idealCore == -1 ) | |
{ | |
this->idealProcessor = -1; | |
KAffinityMask::MakeAllCoresMask(&this->affinityMask); | |
} | |
else | |
{ | |
LABEL_25: | |
this->idealProcessor = idealCore; | |
KProcess::ChangeAffinityMask(&this->affinityMask, idealCore, 1); | |
} | |
LABEL_8: | |
this->tlsUserAddr = 0; | |
this->owner = 0; | |
this->context = 0; | |
this->alive = 0; | |
this->signaled = 0; | |
this->schedulingMask = 1; | |
this->ipcClosedByRemote = 0; | |
p_shallTerminate = &this->shallTerminate; | |
this->debugThread = 0; | |
do | |
__ldrex((unsigned __int8 *)p_shallTerminate); | |
while ( __strex(0, (unsigned __int8 *)p_shallTerminate) ); | |
this->kernelStackTop = (KThreadStackParametersPtr)kernelStackTop; | |
this->dynamicPriority = priority; | |
this->basePriority = priority; | |
if ( threadType == KTHREAD_TYPE_KERNEL_CRITICAL ) | |
v14 = __mrc(15, 0, 0, 0, 5) & 3; | |
else | |
v14 = -1; | |
this->coreId = v14; | |
this->signaledObject = 0; | |
this->synchronizationResult = 0xF960060A; | |
this->wantedLightMutex = 0; | |
this->timeLimit = 0; | |
this->link.prev = 0; | |
this->link.next = 0; | |
this->priorityToRestoreAfterSleep = -1; | |
v15 = parentProcess == 0; | |
v16 = (int)parentProcess <= 0; | |
this->waiterList = 0; | |
if ( parentProcess ) | |
{ | |
reslimit = parentProcess->reslimit; | |
v15 = reslimit == 0; | |
v16 = (int)reslimit <= 0; | |
} | |
if ( !v15 ) | |
v16 = priority <= 15; | |
if ( !v16 ) | |
{ // user process with a thread priority of >= 15? | |
v17 = parentProcess->capability.kernelFlags & 0xF00; | |
v18 = v17 == 256; | |
if ( v17 == 256 ) | |
v18 = this->idealProcessor == 1; | |
if ( !v18 ) | |
{ | |
if ( __PAIR64__(priority, stackTop) == 0x3010000000LL ) | |
{ | |
v27 = ((__int64)parentProcess->codeSet->titleId >> 8) & 0xFFFFF; | |
v28 = v27 == 0x69F; // Tekken 3D Prime Edition (jp, us, eu, kor) | |
if ( v27 != 0x69F ) | |
v28 = v27 == 0x7E9; | |
if ( v28 ) | |
goto LABEL_59; | |
v29 = v27 == 0x803; | |
if ( v27 != 0x803 ) | |
v29 = v27 == 0x91E; | |
if ( v29 ) | |
{ | |
LABEL_59: | |
this->dynamicPriority = 49; | |
this->basePriority = 49; | |
} | |
} | |
goto LABEL_60; | |
} | |
if ( !KResourceLimit::GetLimitValue(reslimit, RESLIMIT_CPUTIME) ) | |
{ | |
if ( parentProcess->capability.intendedKernelVersion > 0x21Eu )// 2.1+ titles and above | |
return 0xE0A01839; | |
KResourceLimit::SetLimitValue(reslimit, RESLIMIT_CPUTIME, 25);// 1.0 titles | |
} | |
if ( g_schedulerAppPreemptionMode != 1 ) | |
{ | |
LABEL_60: | |
this->timeLimit = KResourceLimit::GetTimeLimit(reslimit); | |
goto LABEL_61; | |
} | |
v19 = __ldrex((unsigned int *)&g_threadAllocator.container.mutex); | |
v20 = v19 == 0; | |
if ( v19 ) | |
__strex(v19, (unsigned int *)&g_threadAllocator.container.mutex); | |
else | |
v19 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_threadAllocator.container.mutex); | |
if ( v20 ) | |
v20 = v19 == 0; | |
if ( !v20 ) | |
KLightMutex::LockImpl(&g_threadAllocator.container.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
next = (KThreadLinkedListNode *)g_threadAllocator.container.list.link.next; | |
if ( (KAutoObjectLinkedListLink *)g_threadAllocator.container.list.link.next == &g_threadAllocator.container.list.link ) | |
{ | |
LABEL_44: | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_threadAllocator.container.mutex.lockingThread = 0; | |
if ( g_threadAllocator.container.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_threadAllocator.container.mutex); | |
LimitValue = KResourceLimit::GetLimitValue(reslimit, RESLIMIT_PRIORITY);// set priority = Highest(prio-8, highest prio in reslimit) | |
if ( priority - 8 >= LimitValue ) // priority gets bumped | |
LimitValue = priority - 8; | |
this->dynamicPriority = LimitValue; | |
this->basePriority = LimitValue; | |
goto LABEL_60; | |
} | |
while ( 1 ) | |
{ | |
thread = next->thread; // preemption mode 1 (the bugged one?) doesn't allow for more than 1 app thread on core 1 | |
owner = thread->owner; | |
v24 = owner == parentProcess; | |
if ( owner == parentProcess ) | |
v24 = thread->coreId == 1; | |
if ( v24 ) | |
break; | |
next = next->link.next; | |
if ( next == (KThreadLinkedListNode *)&g_threadAllocator.container.list.link ) | |
goto LABEL_44; | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_threadAllocator.container.mutex.lockingThread = 0; | |
if ( g_threadAllocator.container.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_threadAllocator.container.mutex); | |
return 0xE0A01839; | |
} | |
LABEL_61: | |
if ( threadType == KTHREAD_TYPE_USER ) | |
{ | |
if ( KProcess::AllocateTls(parentProcess, &this->tlsUserAddr) < 0 ) | |
return 0xD86007F3; | |
v30 = KPageTable::ConvertVaToPa(&parentProcess->pgTable.L1Table, this->tlsUserAddr); | |
if ( v30 ) | |
v30 -= -0xC0000000; | |
this->tls = (u32 *)v30; | |
} | |
if ( parentProcess ) | |
{ | |
KProcess::IncrementThreadCount(parentProcess); | |
KAutoObject::IncrementRefcount(parentProcess); | |
this->owner = parentProcess; | |
} | |
v31 = ADJ(this->kernelStackTop) + 1; | |
if ( threadType == KTHREAD_TYPE_USER ) | |
arg = 1; | |
this->context = &ADJ(v31)->ctx; | |
if ( threadType != KTHREAD_TYPE_USER ) | |
arg = 0; | |
KThreadContext::Initialize(&ADJ(v31)->ctx, ep, (u32)ADJ(v31)->svcAcl, stackTop, arg_, arg); | |
v32 = this->owner; | |
v33 = ADJ(this->kernelStackTop); | |
if ( v32 ) | |
{ | |
v34 = v32->capability.svcAcl[0]; | |
v35 = v32->capability.svcAcl[1]; | |
v36 = v32->capability.svcAcl[2]; | |
ADJ(this->kernelStackTop)->svcAcl[3] = v32->capability.svcAcl[3]; | |
v33->svcAcl[0] = v34; | |
v33->svcAcl[1] = v35; | |
v33->svcAcl[2] = v36; | |
v33->allowDebug = this->owner->capability.kernelFlags & 1; | |
} | |
else | |
{ | |
v33->svcAcl[0] = 0; | |
v33->svcAcl[1] = 0; | |
v33->svcAcl[2] = 0; | |
v33->svcAcl[3] = 0; | |
v33->allowDebug = 0; | |
} | |
p_dpcFlags = &v33->dpcFlags; | |
do | |
__ldrex(p_dpcFlags); | |
while ( __strex(0, p_dpcFlags) ); | |
v33->unk = 0; | |
do | |
v38 = __ldrex(&g_threadIdCounter); | |
while ( __strex(v38 + 1, &g_threadIdCounter) ); | |
this->threadId = v38; | |
return 0; | |
} | |
// FFF153B8: variable 'reslimit' is possibly undefined | |
// FFF155A0: variable 'arg' is possibly undefined | |
//----- (FFF15664) -------------------------------------------------------- | |
void __fastcall _aeabi_memset4(void *data, u8 value, u32 size) | |
{ | |
bool v3; // cf | |
unsigned int v4; // r1 | |
u32 *v5; // r0 | |
int v6; // r1 | |
int v7; // r1 | |
v3 = value >= 0x20u; | |
v4 = value - 32; | |
do | |
{ | |
if ( !v3 ) | |
break; | |
*(_DWORD *)data = size; | |
*((_DWORD *)data + 1) = size; | |
*((_DWORD *)data + 2) = size; | |
*((_DWORD *)data + 3) = size; | |
v5 = (u32 *)((char *)data + 16); | |
*v5 = size; | |
v5[1] = size; | |
v5[2] = size; | |
v5[3] = size; | |
data = v5 + 4; | |
v3 = v4 >= 0x20; | |
v4 -= 32; | |
} | |
while ( v3 ); | |
v3 = __CFSHL__(v4, 28); | |
v6 = v4 << 28; | |
if ( v3 ) | |
{ | |
*(_DWORD *)data = size; | |
*((_DWORD *)data + 1) = size; | |
*((_DWORD *)data + 2) = size; | |
*((_DWORD *)data + 3) = size; | |
data = (char *)data + 16; | |
} | |
if ( v6 < 0 ) | |
{ | |
*(_DWORD *)data = size; | |
*((_DWORD *)data + 1) = size; | |
data = (char *)data + 8; | |
} | |
v3 = __CFSHL__(v6, 2); | |
v7 = 4 * v6; | |
if ( v3 ) | |
{ | |
*(_DWORD *)data = size; | |
data = (char *)data + 4; | |
} | |
if ( v7 ) | |
{ | |
if ( v7 < 0 ) | |
{ | |
*(_WORD *)data = size; | |
data = (char *)data + 2; | |
} | |
if ( (v7 & 0x40000000) != 0 ) | |
*(_BYTE *)data = size; | |
} | |
} | |
//----- (FFF156B4) -------------------------------------------------------- | |
BOOL __fastcall CopyBytesFromUser(void *dst, const void *src, u32 size) | |
{ | |
bool v3; // zf | |
char *v5; // r3 | |
char v6; // r2 | |
v3 = size == 0; | |
if ( !size ) | |
return 1; | |
v5 = (char *)src + size; | |
do | |
{ | |
src = (char *)src + 1; | |
v6 = __ldrt((unsigned int *)src); | |
if ( !v3 ) | |
v3 = src == v5; | |
*(_BYTE *)dst = v6; | |
dst = (char *)dst + 1; | |
} | |
while ( !v3 ); | |
return 1; | |
} | |
//----- (FFF156E4) -------------------------------------------------------- | |
BOOL __fastcall CopyWordsFromUser(void *dst, const void *src, u32 size) | |
{ | |
bool v3; // zf | |
char *v5; // r3 | |
unsigned int v6; // r2 | |
v3 = size == 0; | |
if ( !size ) | |
return 1; | |
v5 = (char *)src + size; | |
do | |
{ | |
src = (char *)src + 4; | |
v6 = __ldrt((unsigned int *)src); | |
if ( !v3 ) | |
v3 = src == v5; | |
*(_DWORD *)dst = v6; | |
dst = (char *)dst + 4; | |
} | |
while ( !v3 ); | |
return 1; | |
} | |
//----- (FFF15714) -------------------------------------------------------- | |
BOOL __fastcall CopyWordFromUser(void *dst, const void *src) | |
{ | |
unsigned int v2; // r2 | |
v2 = __ldrt((unsigned int *)src); | |
*(_DWORD *)dst = v2; | |
return 1; | |
} | |
//----- (FFF1572C) -------------------------------------------------------- | |
int __fastcall CopyStringFromUser(char *dstStr, const char *srcStr, u32 size) | |
{ | |
bool v3; // zf | |
const char *v5; // r4 | |
const char *v6; // r3 | |
unsigned int v7; // r2 | |
v3 = size == 0; | |
if ( !size ) | |
return 0; | |
v5 = srcStr; | |
v6 = &srcStr[size]; | |
do | |
{ | |
v7 = __ldrt((unsigned int *)++srcStr); | |
if ( !v3 ) | |
v3 = srcStr == v6; | |
*dstStr++ = v7; | |
if ( v3 ) | |
break; | |
v3 = v7 == 0; | |
} | |
while ( v7 ); | |
return srcStr - v5; | |
} | |
//----- (FFF1576C) -------------------------------------------------------- | |
BOOL __fastcall CopyBytesToUser(void *dst, const void *src, u32 size) | |
{ | |
char *v4; // r3 | |
unsigned __int8 v5; // t1 | |
if ( !size ) | |
return 1; | |
v4 = (char *)src + size; | |
do | |
{ | |
v5 = *(_BYTE *)src; | |
src = (char *)src + 1; | |
__strt(v5, (unsigned __int8 *)dst); | |
dst = (char *)dst + 1; | |
} | |
while ( src != v4 ); | |
return 1; | |
} | |
//----- (FFF1579C) -------------------------------------------------------- | |
BOOL __fastcall CopyWordsToUser(void *dst, const void *src, u32 dataSize) | |
{ | |
char *v4; // r3 | |
unsigned int v5; // t1 | |
if ( !dataSize ) | |
return 1; | |
v4 = (char *)src + dataSize; | |
do | |
{ | |
v5 = *(_DWORD *)src; | |
src = (char *)src + 4; | |
__strt(v5, (unsigned int *)dst); | |
dst = (char *)dst + 4; | |
} | |
while ( src != v4 ); | |
return 1; | |
} | |
//----- (FFF157CC) -------------------------------------------------------- | |
BOOL __fastcall CopyWordToUser(void *dst, const void *src) | |
{ | |
__strt(*(_DWORD *)src, (unsigned int *)dst); | |
return 1; | |
} | |
//----- (FFF157E4) -------------------------------------------------------- | |
int __fastcall CopyStringToUser(char *dstStr, const char *srcStr, u32 size) | |
{ | |
char *v4; // r4 | |
const char *v5; // r3 | |
int v6; // r2 | |
int v7; // t1 | |
bool v8; // zf | |
if ( !size ) | |
return 0; | |
v4 = dstStr; | |
v5 = &srcStr[size]; | |
do | |
{ | |
v7 = *(unsigned __int8 *)srcStr++; | |
v6 = v7; | |
v8 = srcStr == v5; | |
__strt(v7, (unsigned __int8 *)dstStr++); | |
if ( srcStr != v5 ) | |
v8 = v6 == 0; | |
} | |
while ( !v8 ); | |
return srcStr - v4; | |
} | |
//----- (FFF15824) -------------------------------------------------------- | |
BOOL __fastcall ClearUserBytes(void *userBuffer, u32 size) | |
{ | |
bool v2; // zf | |
char *v4; // r3 | |
v2 = size == 0; | |
if ( !size ) | |
return 1; | |
v4 = (char *)userBuffer + size; | |
do | |
{ | |
__strt(0, (unsigned __int8 *)userBuffer); | |
userBuffer = (char *)userBuffer + 1; | |
if ( v2 ) | |
break; | |
v2 = userBuffer == v4; | |
} | |
while ( userBuffer != v4 ); | |
return 1; | |
} | |
//----- (FFF15854) -------------------------------------------------------- | |
BOOL __fastcall ClearUserWords(void *userBuffer, u32 size) | |
{ | |
bool v2; // zf | |
char *v4; // r3 | |
v2 = size == 0; | |
if ( !size ) | |
return 1; | |
v4 = (char *)userBuffer + size; | |
do | |
{ | |
__strt(0, (unsigned int *)userBuffer); | |
userBuffer = (char *)userBuffer + 4; | |
if ( v2 ) | |
break; | |
v2 = userBuffer == v4; | |
} | |
while ( userBuffer != v4 ); | |
return 1; | |
} | |
//----- (FFF15884) -------------------------------------------------------- | |
BOOL __fastcall ClearUserWord(void *userBuffer) | |
{ | |
__strt(0, (unsigned int *)userBuffer); | |
return 1; | |
} | |
//----- (FFF1589C) -------------------------------------------------------- | |
bool __fastcall KDmaAddress::ResetAddress(KDmaAddress *this, u32 newAddr) | |
{ | |
int align1; // r5 | |
int newAlign; // r4 | |
u32 maxVa; // r0 | |
u32 v6; // r1 | |
u32 **p_L1Table; // r0 | |
bool v8; // cc | |
align1 = 0; // check if old alignment can still be used | |
newAlign = 0; | |
if ( newAddr ) | |
{ | |
maxVa = this->maxVa; | |
if ( maxVa ) | |
{ | |
for ( align1 = 1; (maxVa & align1) == 0; align1 *= 2 ) | |
; | |
} | |
else | |
{ | |
align1 = 0; | |
} | |
for ( newAlign = 1; (newAddr & newAlign) == 0; newAlign *= 2 ) | |
; | |
this->maxVa = newAddr; | |
} | |
v6 = this->maxVa; | |
p_L1Table = &this->process->pgTable.L1Table; | |
this->currentVa = v6; | |
this->currentPa = KPageTable::ConvertVaToPa(p_L1Table, v6); | |
if ( align1 == newAlign ) | |
return 1; | |
v8 = align1 < 8; | |
if ( align1 >= 8 ) | |
v8 = newAlign < 8; | |
return !v8; // misaligned | |
} | |
// FFF158E4: conditional instruction was optimized away because r1.4!=0 | |
//----- (FFF1593C) -------------------------------------------------------- | |
KAutoObject *__fastcall KAutoObject::KAutoObject(KAutoObject *this) | |
{ | |
this->__vftable = &KAutoObject::vt; | |
this->refcount = 0; | |
return this; | |
} | |
//----- (FFF15950) -------------------------------------------------------- | |
Result __fastcall KProcessPageTable::MapStaticOrIo( | |
KProcessPageTable *this, | |
u32 addr, | |
u32 size, | |
BOOL isIo, | |
KMemoryPermission userPerms) | |
{ | |
bool v6; // cf | |
u32 v7; // r3 | |
u32 v8; // r3 | |
bool v9; // cf | |
bool v10; // cf | |
KMemoryState v12; // r4 | |
v6 = addr >= 0x1F000000; // this function is extremely similar to KProcessPageTable::MapStaticOrIoExheaderRange | |
v7 = addr + (size << 12); | |
if ( addr >= 0x1F000000 ) | |
v6 = v7 <= 0x1F600000; | |
if ( v6 ) | |
{ | |
v8 = addr - 0x7000000; | |
} | |
else if ( addr < 0x1EC00000 || v7 > 0x1FC00000 ) | |
{ | |
v9 = addr >= 0x1FF00000; | |
if ( addr >= 0x1FF00000 ) | |
v9 = v7 <= 0x1FF80000; | |
if ( v9 ) | |
{ | |
v8 = addr; | |
} | |
else | |
{ | |
v10 = addr >= 0x1E800000; | |
if ( addr >= 0x1E800000 ) | |
v10 = v7 <= 0x1EBE0000; | |
if ( v10 ) | |
v8 = addr + 0x800000; | |
else | |
v8 = 0; | |
} | |
} | |
else | |
{ | |
v8 = addr - 0xEB00000; | |
} | |
if ( !v8 ) | |
return 0xE0E01BF5; | |
if ( isIo ) | |
v12 = KMEMSTATE_IO; | |
else | |
v12 = KMEMSTATE_STATIC; | |
return KPageTable::Operate( | |
this, | |
addr, | |
size, | |
v8, | |
v12, | |
(KMemoryPermission)(userPerms | KMEMPERM_KRW), | |
KMEMUPDATE_NONE, | |
MEMOP_REGION_BASE); | |
} | |
//----- (FFF15A0C) -------------------------------------------------------- | |
Result __fastcall KDebug::SetThreadVfpContext( | |
KDebug *this, | |
ThreadContext *threadContext, | |
KThread *thread, | |
ThreadContextControlFlags flags) | |
{ | |
unsigned int CPSR; // r4 | |
__int32 v6; // r6 | |
KThreadContext *context; // r7 | |
s32 v8; // r0 | |
char cfgr; // r1 | |
Result result; // r0 | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
v6 = flags & 0xFFFFF; | |
if ( (flags & THREADCONTEXT_CONTROL_FPU_REGS) != 0 ) | |
{ | |
context = thread->context; | |
v8 = 0; | |
cfgr = MPCORE.scu.cfgr; | |
while ( (cfgr & 3) + 1 > v8 ) | |
{ | |
if ( thread == *(KThread **)(0x9000 * v8 + 0xFFFD1010) ) | |
{ | |
KVfpRegisterDumpHelper::DumpAndDisableVfpRegsForCore(v8);// current thread with vfp enabled | |
break; | |
} | |
++v8; | |
} | |
if ( (v6 & THREADCONTEXT_CONTROL_FPU_SPRS_ALLFLAGS) != 0 ) | |
{ | |
context->fpexc = threadContext->fpuRegisters.fpexc & ~0x40000000u;// clear the enable bit | |
context->fpscr = threadContext->fpuRegisters.fpscr; | |
} | |
if ( (v6 & THREADCONTEXT_CONTROL_FPU_GPRS_ALLFLAGS) != 0 ) | |
KThreadContext::SetVfpGprs(context, threadContext->fpuRegisters.d); | |
} | |
result = 0; | |
__set_CPSR(CPSR); | |
return result; | |
} | |
//----- (FFF15ACC) -------------------------------------------------------- | |
bool __fastcall KResourceLimit::Reserve(KResourceLimit *this, ResourceLimitType category, s32 amount) | |
{ | |
unsigned int *p_mutex; // r0 | |
KLightMutex *v7; // r4 | |
unsigned int v8; // r2 | |
bool v9; // zf | |
unsigned int v10; // r3 | |
KAutoObject_vtbl **v11; // r0 | |
s32 v12; // r2 | |
p_mutex = (unsigned int *)&this->mutex; | |
v7 = (KLightMutex *)p_mutex; | |
v8 = __ldrex(p_mutex); | |
v9 = v8 == 0; | |
if ( v8 ) | |
v10 = __strex(v8, p_mutex); | |
else | |
v10 = __strex((unsigned int)current.clc.current.thread, p_mutex); | |
if ( !v8 ) | |
v9 = v10 == 0; | |
if ( !v9 ) | |
KLightMutex::LockImpl((KLightMutex *)p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
v11 = &this->__vftable + category; | |
v12 = (s32)v11[12] + amount; | |
if ( v12 > (int)v11[2] ) | |
{ | |
__mcr(15, 0, 0, 7, 10, 5); | |
v7->lockingThread = 0; | |
if ( v7->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v7); | |
return 0; | |
} | |
else | |
{ | |
v11[12] = (KAutoObject_vtbl *)v12; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v7->lockingThread = 0; | |
if ( v7->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v7); | |
return 1; | |
} | |
} | |
//----- (FFF15B6C) -------------------------------------------------------- | |
bool __fastcall KDmaAddress::CheckBufferRangeValid(KDmaAddress *this, s32 minOffset, s32 maxOffset) | |
{ | |
u32 currentVa; // r3 | |
currentVa = this->currentVa; // if isDevice any va !=0 is valid (why?????) | |
// | |
// otherwise check for overflow/underflow | |
// | |
// arm9: only check if != 0 | |
return currentVa | |
&& (this->isDevice || (maxOffset <= 0 || currentVa - 1 <= ~maxOffset) | |
&& (minOffset >= 0 || currentVa > -minOffset)); | |
} | |
//----- (FFF15BC0) -------------------------------------------------------- | |
bool __fastcall KDmaAddress::CheckVirtualAddressBlockUsable( | |
KDmaAddress *this, | |
s32 minOffset, | |
s32 maxOffset, | |
BOOL writePerms) | |
{ | |
u32 startCheckVa; // r5 | |
unsigned __int32 totalSize; // r6 | |
bool result; // r0 | |
KMemoryInfo info; // [sp+0h] [bp-28h] BYREF | |
u32 pageInfo; // [sp+10h] [bp-18h] BYREF | |
startCheckVa = this->currentVa + minOffset; | |
totalSize = maxOffset - minOffset; // lgy_firm k11 walks the translation table directly, iirc (need to check) | |
if ( KPageTable::QueryInfo(&this->process->pgTable, &info, &pageInfo, startCheckVa) < 0 | |
|| !this->isDevice && totalSize && info.baseAddress + info.size - startCheckVa < totalSize ) | |
{ | |
return 0; | |
} | |
result = MEMSTATE_FREE; // 0 | |
if ( (info.state & KMEMSTATE_FLAG_MAPPED) != 0 ) | |
{ | |
if ( writePerms ) | |
{ | |
result = info.perms & KMEMPERM_W; | |
if ( (info.perms & KMEMPERM_W) != 0 ) | |
return 1; | |
} | |
else | |
{ | |
result = info.perms & KMEMPERM_R; | |
if ( (info.perms & KMEMPERM_R) != 0 ) | |
return 1; | |
} | |
} | |
return result; | |
} | |
//----- (FFF15C68) -------------------------------------------------------- | |
KSynchronizationObject *__fastcall KSynchronizationObject::KSynchronizationObject(KSynchronizationObject *this) | |
{ | |
KSynchronizationObject *result; // r0 | |
result = (KSynchronizationObject *)KAutoObject::KAutoObject(this); | |
result->waiters.count = 0; | |
result->__vftable = &KSynchronizationObject::vt; | |
result->waiters.link.next = (KThreadLinkedListNode *)&result->waiters.link; | |
result->waiters.link.prev = (KThreadLinkedListNode *)&result->waiters.link; | |
return result; | |
} | |
//----- (FFF15C94) -------------------------------------------------------- | |
Result __fastcall KObjectAllocator::Register(KObjectAllocator *this, KAutoObject *obj) | |
{ | |
KLightMutex *p_mutex; // r0 | |
KLightMutex *v5; // r4 | |
unsigned int v6; // r2 | |
bool v7; // zf | |
unsigned int v8; // r3 | |
KLinkedListNode *v9; // r0 | |
p_mutex = &this->container.mutex; | |
v5 = p_mutex; | |
v6 = __ldrex((unsigned int *)p_mutex); | |
v7 = v6 == 0; | |
if ( v6 ) | |
v8 = __strex(v6, (unsigned int *)p_mutex); | |
else | |
v8 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)p_mutex); | |
if ( !v6 ) | |
v7 = v8 == 0; | |
if ( !v7 ) | |
KLightMutex::LockImpl(p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
v9 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v9 ) | |
{ | |
v9->link.next = 0; | |
v9->link.prev = 0; | |
v9->data = 0; | |
} | |
v9->data = obj; | |
KLinkedList::InsertAfter((KLinkedList *)this, (KLinkedListLink *)&this->container.list.link, v9); | |
if ( this->container.list.count > this->count ) | |
this->count = this->container.list.count; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v5->lockingThread = 0; | |
if ( v5->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v5); | |
return 0; | |
} | |
// FFF15CF8: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF15D58) -------------------------------------------------------- | |
void __fastcall KPageGroup::IncrefPages(KPageGroup *this) | |
{ | |
KBlockInfoLinkedListNode *node; // r5 | |
KBlockInfo *blockInfo; // r3 | |
unsigned int v4; // r2 | |
u32 baseAddress; // r9 | |
u32 numPages; // r10 | |
bool v7; // zf | |
unsigned int v8; // r3 | |
for ( node = this->list.link.next; node != (KBlockInfoLinkedListNode *)&this->list.link; node = node->link.next ) | |
{ | |
blockInfo = node->blockInfo; | |
v4 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
baseAddress = blockInfo->baseAddress; | |
numPages = blockInfo->numPages; | |
v7 = v4 == 0; | |
if ( v4 ) | |
v8 = __strex(v4, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v8 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v4 ) | |
v7 = v8 == 0; | |
if ( !v7 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, baseAddress, numPages); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
} | |
} | |
//----- (FFF15DE4) -------------------------------------------------------- | |
Result __fastcall KPageTable::CheckAndMapPageGroup( | |
KProcessPageTable *this, | |
u32 addr, | |
KPageGroup *pgGroup, | |
KMemoryState state, | |
KMemoryPermission perms) | |
{ | |
u32 TotalNumPages; // r0 | |
Result result; // r0 | |
TotalNumPages = KPageGroup::GetTotalNumPages(pgGroup); | |
result = KPageTable::CheckMemoryBlockAttributes(this, addr, TotalNumPages << 12, MEMSTATE_FREE, KMEMPERM_NONE); | |
if ( result >= 0 ) | |
return KPageTable::OperateOnGroup(this, addr, pgGroup, state, (KMemoryPermission)(perms | 0x18), KMEMUPDATE_NONE); | |
return result; | |
} | |
//----- (FFF15E54) -------------------------------------------------------- | |
void __fastcall KPageHeap::FreeBlock(KPageHeap *this, u32 addr, u32 numPages) | |
{ | |
KPageHeapBlock *next; // r4 | |
KPageHeapBlock *nextBlock; // r5 | |
KPageHeapBlock *i; // r4 | |
if ( numPages && !KPageHeap::TryInsert(this, addr, numPages, 0, this->link.next) ) | |
{ | |
next = this->link.next; | |
if ( !this->link.next ) | |
{ | |
LABEL_6: | |
for ( i = this->link.next; i; i = i->link.next ) | |
KPageHeap::ValidateBlock(this, i); | |
kernelpanic(); | |
} | |
while ( 1 ) | |
{ | |
KPageHeap::ValidateBlock(this, next); | |
nextBlock = next->link.next; | |
KPageHeap::ValidateBlock(this, nextBlock); | |
if ( KPageHeap::TryInsert(this, addr, numPages, next, nextBlock) ) | |
break; | |
next = next->link.next; | |
if ( !next ) | |
goto LABEL_6; | |
} | |
} | |
} | |
//----- (FFF15F14) -------------------------------------------------------- | |
Result __fastcall ControlSystem(SystemOperation op, u32 arg1, u64 arg2) | |
{ | |
u32 param2Lo; // r5 | |
unsigned int param2Hi; // r6 | |
unsigned int v7; // r2 | |
bool v8; // zf | |
unsigned int v9; // r3 | |
char cfgr; // r0 | |
char v11; // r0 | |
Result v12; // r5 | |
Result v13; // r0 | |
KProcessPageTable *p_pgTable; // r6 | |
u32 v15; // r0 | |
char v16; // r0 | |
char v17; // r0 | |
char v18; // r0 | |
param2Hi = HIDWORD(arg2); | |
param2Lo = arg2; | |
v7 = __ldrex((unsigned int *)&g_systemControl.mutex); | |
v8 = v7 == 0; | |
if ( v7 ) | |
v9 = __strex(v7, (unsigned int *)&g_systemControl.mutex); | |
else | |
v9 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_systemControl.mutex); | |
if ( !v7 ) | |
v8 = v9 == 0; | |
if ( !v8 ) | |
KLightMutex::LockImpl(&g_systemControl.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
switch ( op ) | |
{ | |
case SYSTEMOP_FIRMLAUNCH: | |
g_systemControl.operation = op; | |
if ( !(param2Lo ^ 2 | param2Hi) ) // if ((titleId ^ 2) == 0) (native firm) | |
param2Lo = param2Lo & 0xFFFFFFF | 0x20000000; | |
LODWORD(g_systemControl.firmlaunchTitleId) = param2Lo; | |
HIDWORD(g_systemControl.firmlaunchTitleId) = 0x40138; | |
KDmaManager::AbortAll(&g_dmaManager); | |
cfgr = MPCORE.scu.cfgr; | |
MPCORE.gicd.sgir = (((1 << ((cfgr & 3) + 1)) - 1) << 16) & 0xFF0000 | 6; | |
goto LABEL_13; | |
case SYSTEMOP_UNIMPLEMENTED_1: | |
v12 = 0; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_systemControl.mutex.lockingThread = 0; | |
if ( g_systemControl.mutex.numWaiters > 0 ) | |
goto LABEL_20; | |
return v12; | |
case SYSTEMOP_SLEEP: | |
g_systemControl.operation = op; | |
g_systemControl.srcCoreId = __mrc(15, 0, 0, 0, 5) & 3; | |
KDmaManager::AbortAll(&g_dmaManager); | |
v16 = MPCORE.scu.cfgr; | |
MPCORE.gicd.sgir = (((1 << ((v16 & 3) + 1)) - 1) << 16) & 0xFF0000 | 6; | |
v12 = 0; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_systemControl.mutex.lockingThread = 0; | |
if ( g_systemControl.mutex.numWaiters > 0 ) | |
goto LABEL_20; | |
return v12; | |
case SYSTEMOP_DELIVER_PARAMETERS: | |
if ( arg1 ) | |
{ | |
if ( arg1 == 1 ) | |
{ | |
qmemcpy((void *)0xE0000000, (const void *)g_systemControl.deliverParamsPage, 0x1000u); | |
v13 = 0; | |
} | |
else | |
{ | |
v13 = 0xF8C007F4; | |
} | |
} | |
else if ( __PAIR64__(param2Hi, param2Lo) < 0x10000000 || __PAIR64__(param2Hi, param2Lo) >= 0x14000000 ) | |
{ | |
v13 = 0xE0E01BF5; // 11.14 security fix | |
// you could map the NULL page before | |
} | |
else | |
{ | |
p_pgTable = ¤t.clc.current.process->pgTable; | |
v15 = KPageTable::ConvertVaToPa(&g_supervisorPageTable.L1Table, g_systemControl.deliverParamsPage); | |
v13 = KPageTable::Operate( | |
p_pgTable, | |
param2Lo, | |
1u, | |
v15, | |
KMEMSTATE_SHARED, | |
KMEMPERM_KRW_RW, | |
KMEMUPDATE_NONE, | |
0x300u); | |
} | |
v12 = v13; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_systemControl.mutex.lockingThread = 0; | |
if ( g_systemControl.mutex.numWaiters > 0 ) | |
goto LABEL_20; | |
return v12; | |
case SYSTEMOP_POWER_STATE_CHANGE_SCHEDULING: | |
g_systemControl.param1 = arg1; | |
g_systemControl.operation = op; | |
LOBYTE(g_systemControl.srcCoreId) = __mrc(15, 0, 0, 0, 5) & 3; | |
g_systemControl.srcCoreId = LOBYTE(g_systemControl.srcCoreId); | |
v18 = MPCORE.scu.cfgr; | |
MPCORE.gicd.sgir = (((1 << ((v18 & 3) + 1)) - 1) << 16) & 0xFF0000 | 6; | |
v12 = 0; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_systemControl.mutex.lockingThread = 0; | |
if ( g_systemControl.mutex.numWaiters <= 0 ) | |
return v12; | |
goto LABEL_20; | |
case SYSTEMOP_MISC: | |
if ( !g_systemControl.unitInfo ) | |
goto LABEL_28; | |
if ( arg1 == 1 ) | |
{ | |
g_systemControl.targetSystem.userExceptionHandlersEnabled = (param2Lo | param2Hi) != 0; | |
} | |
else if ( arg1 == 2 ) | |
{ | |
g_systemControl.targetSystem.kernelPanicOnUserBreak = (param2Lo | param2Hi) != 0; | |
} | |
else | |
{ | |
LABEL_28: | |
if ( arg1 == 3 ) | |
{ | |
v12 = KScheduler::ChangeAppPreemptionMode(param2Lo); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_systemControl.mutex.lockingThread = 0; | |
if ( g_systemControl.mutex.numWaiters > 0 ) | |
goto LABEL_20; | |
return v12; | |
} | |
} | |
v12 = 0; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_systemControl.mutex.lockingThread = 0; | |
if ( g_systemControl.mutex.numWaiters > 0 ) | |
LABEL_20: | |
KLightMutex::UnlockImpl(&g_systemControl.mutex); | |
return v12; | |
case SYSTEMOP_HARDWARE_RESET: | |
g_systemControl.operation = op; | |
g_systemControl.srcCoreId = __mrc(15, 0, 0, 0, 5) & 3; | |
KDmaManager::AbortAll(&g_dmaManager); | |
v11 = MPCORE.scu.cfgr; | |
MPCORE.gicd.sgir = (((1 << ((v11 & 3) + 1)) - 1) << 16) & 0xFF0000 | 6; | |
goto LABEL_13; | |
case SYSTEMOP_HANG_ARM9: | |
if ( !arg1 ) | |
{ | |
*g_systemControl.pxi.send = 0x348E43; | |
*g_systemControl.pxi.sync = 0x80; | |
while ( (*g_systemControl.pxi.cnt & 0x100) != 0 ) | |
; | |
if ( *g_systemControl.pxi.recv != 0xAEE97647 ) | |
kernelpanic(); | |
} | |
v12 = 0; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_systemControl.mutex.lockingThread = 0; | |
if ( g_systemControl.mutex.numWaiters > 0 ) | |
goto LABEL_20; | |
return v12; | |
case SYSTEMOP_SET_TITLEID_FOR_SMALL_PAGES_WORKAROUND: | |
LODWORD(g_systemControl.titleIdForSmallPageWorkaround) = param2Lo; | |
HIDWORD(g_systemControl.titleIdForSmallPageWorkaround) = param2Hi; | |
v12 = 0; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_systemControl.mutex.lockingThread = 0; | |
if ( g_systemControl.mutex.numWaiters > 0 ) | |
goto LABEL_20; | |
return v12; | |
case SYSTEMOP_CONFIGURE_N3DS_CPU_L2C: | |
g_systemControl.param1 = arg1; | |
g_systemControl.operation = op; | |
LOBYTE(g_systemControl.srcCoreId) = __mrc(15, 0, 0, 0, 5) & 3; | |
g_systemControl.srcCoreId = LOBYTE(g_systemControl.srcCoreId); | |
v17 = MPCORE.scu.cfgr; | |
MPCORE.gicd.sgir = (((1 << ((v17 & 3) + 1)) - 1) << 16) & 0xFF0000 | 6; | |
v12 = 0; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_systemControl.mutex.lockingThread = 0; | |
if ( g_systemControl.mutex.numWaiters > 0 ) | |
goto LABEL_20; | |
return v12; | |
default: | |
LABEL_13: | |
v12 = 0xF8C007F4; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_systemControl.mutex.lockingThread = 0; | |
if ( g_systemControl.mutex.numWaiters > 0 ) | |
goto LABEL_20; | |
return v12; | |
} | |
} | |
// FFF15F64: control flows out of bounds to FFF15F68 | |
// FFF2E000: using guessed type int dword_FFF2E000; | |
//----- (FFF1642C) -------------------------------------------------------- | |
void __fastcall KDmaAddress::Initialize(KDmaAddress *this, u32 dstAddr, bool isDevice, KProcess *process) | |
{ | |
this->isDevice = isDevice; | |
this->process = process; | |
this->maxVa = dstAddr; | |
this->currentVa = dstAddr; | |
this->currentPa = KPageTable::ConvertVaToPa(&process->pgTable.L1Table, dstAddr); | |
} | |
//----- (FFF16454) -------------------------------------------------------- | |
void __fastcall KDmaBufferSize::ComputeFromConfig(KDmaBufferSize *this, s32 size, DmaDeviceConfig *cfg) | |
{ | |
s32 transferSize; // r8 | |
s32 burstSize; // r7 | |
int burstStride; // r1 | |
__int64 intervals; // r10 | |
bool v9; // cc | |
s32 maxOffset; // r0 | |
s32 v11; // r1 | |
s32 minOffset; // r2 | |
s32 v13; // r0 | |
s32 v14; // r2 | |
s32 v15; // r3 | |
s32 v16; // r3 | |
s32 v17; // r2 | |
s32 v18; // r0 | |
int v19; // r0 | |
s32 v20; // r1 | |
s32 v21; // r0 | |
s32 v22; // r0 | |
s32 v23; // r3 | |
s32 v24; // r3 | |
s32 v25; // r2 | |
s32 v26; // r0 | |
int v27; // r6 | |
int v28; // r5 | |
int v29; // r0 | |
int v30; // r0 | |
__int64 v31; // r0 | |
s32 pos; // r3 | |
s32 v33; // r0 | |
s32 v34; // r1 | |
s32 v35; // r0 | |
int v36; // r1 | |
s32 v37; // r1 | |
s32 v38; // r2 | |
s32 v39; // r2 | |
s32 v40; // r3 | |
__int64 v41; // r0 | |
s32 v42; // r1 | |
s32 v43; // r0 | |
s32 v44; // r2 | |
s32 v45; // r0 | |
int v46; // r0 | |
int v47; // r0 | |
s32 v48; // r3 | |
s32 v49; // r12 | |
s32 v50; // lr | |
s32 v51; // r3 | |
s32 v52; // r2 | |
s32 v53; // r12 | |
s32 v54; // r2 | |
s32 v55; // r0 | |
KDmaBufferSize *v56; // r1 | |
int v57; // r2 | |
s32 v58; // [sp+0h] [bp-28h] | |
transferSize = cfg->transferSize; | |
burstSize = cfg->burstSize; | |
burstStride = cfg->burstStride; | |
LODWORD(intervals) = cfg->transferStride - transferSize; | |
this->pos = 0; | |
v9 = burstSize <= 0; | |
this->minOffset = 0; | |
if ( burstSize <= 0 ) | |
v9 = transferSize <= 0; | |
HIDWORD(intervals) = burstStride - burstSize; | |
this->maxOffset = 0; | |
if ( !v9 && intervals ) | |
{ | |
if ( burstSize <= 0 || burstSize == transferSize )// (burstSize <= 0 && transferUnit <= 0) || (transferInterval == 0 && burstInterval == 0) | |
// | |
// with interval = stride - size (or unit) | |
// | |
// "no stride" case | |
{ | |
maxOffset = size / transferSize; | |
v11 = size / transferSize; | |
if ( size / transferSize <= 0 ) | |
goto LABEL_107; | |
this->pos = transferSize; | |
if ( transferSize >= 0 ) | |
maxOffset = this->maxOffset; | |
if ( transferSize > 0 ) | |
maxOffset = transferSize; | |
if ( transferSize >= 0 ) | |
this->maxOffset = maxOffset; | |
else | |
this->minOffset = transferSize; | |
minOffset = this->minOffset; | |
v13 = transferSize + intervals; | |
this->pos = transferSize + intervals; | |
if ( transferSize + (int)intervals >= minOffset ) | |
{ | |
if ( this->maxOffset >= v13 ) | |
v13 = this->maxOffset; | |
this->maxOffset = v13; | |
} | |
else | |
{ | |
this->minOffset = v13; | |
} | |
if ( v11 - 1 > 0 ) | |
{ | |
v14 = this->pos * (v11 - 1); | |
if ( this->pos > 0 ) | |
v15 = this->maxOffset; | |
else | |
v15 = this->minOffset; | |
v16 = v15 + v14 - this->pos; | |
if ( this->pos > 0 ) | |
this->maxOffset = v16; | |
else | |
this->minOffset = v16; | |
this->pos = v14; | |
} | |
else | |
{ | |
this->pos = 0; | |
this->minOffset = 0; | |
this->maxOffset = 0; | |
} | |
v17 = this->minOffset; | |
v18 = this->pos + transferSize; | |
this->pos = v18; | |
if ( v18 >= v17 ) | |
{ | |
if ( this->maxOffset >= v18 ) | |
v18 = this->maxOffset; | |
this->maxOffset = v18; | |
} | |
else | |
{ | |
this->minOffset = v18; | |
} | |
v19 = transferSize * v11; | |
goto LABEL_106; | |
} | |
if ( transferSize > 0 ) | |
{ | |
v58 = size / transferSize; | |
v27 = 0; | |
v28 = burstSize; | |
if ( burstStride >= 0 ) | |
{ | |
if ( burstSize < burstStride ) | |
v28 = burstStride; | |
} | |
else | |
{ | |
v27 = burstStride; | |
} | |
v29 = transferSize / burstSize - 1; | |
if ( v29 > 0 ) | |
{ | |
v30 = burstStride * v29; | |
v9 = burstStride <= 0; | |
v36 = v30 - burstStride; | |
if ( v9 ) | |
v27 += v36; | |
else | |
v28 += v36; | |
} | |
else | |
{ | |
v27 = 0; | |
v30 = 0; | |
v28 = 0; | |
} | |
HIDWORD(intervals) = v30 + burstSize; | |
if ( v30 + burstSize >= v27 ) | |
{ | |
if ( v28 < SHIDWORD(intervals) ) | |
v28 = v30 + burstSize; | |
} | |
else | |
{ | |
v27 = v30 + burstSize; | |
} | |
if ( v58 > 0 ) | |
{ | |
v31 = *(_QWORD *)&this->pos; | |
pos = this->pos; | |
if ( this->minOffset >= this->pos + v27 ) | |
HIDWORD(v31) = this->pos + v27; | |
LODWORD(v31) = this->maxOffset; | |
this->minOffset = HIDWORD(v31); | |
HIDWORD(v31) = pos + v28; | |
if ( (int)v31 >= pos + v28 ) | |
v34 = v33; | |
this->maxOffset = v34; | |
v35 = this->pos + HIDWORD(intervals) + intervals; | |
this->pos = v35; | |
if ( v35 >= this->minOffset ) | |
{ | |
if ( this->maxOffset >= v35 ) | |
v35 = this->maxOffset; | |
this->maxOffset = v35; | |
} | |
else | |
{ | |
this->minOffset = v35; | |
} | |
if ( v58 - 1 > 0 ) | |
{ | |
v37 = this->pos * (v58 - 1); | |
if ( this->pos > 0 ) | |
v38 = this->maxOffset; | |
else | |
v38 = this->minOffset; | |
v39 = v38 + v37 - this->pos; | |
if ( this->pos > 0 ) | |
this->maxOffset = v39; | |
else | |
this->minOffset = v39; | |
this->pos = v37; | |
} | |
else | |
{ | |
this->pos = 0; | |
this->minOffset = 0; | |
this->maxOffset = 0; | |
} | |
v41 = *(_QWORD *)&this->pos; | |
v40 = this->pos; | |
LODWORD(v41) = this->pos + v27; | |
if ( this->minOffset < (int)v41 ) | |
LODWORD(v41) = HIDWORD(v41); | |
HIDWORD(v41) = this->maxOffset; | |
this->minOffset = v41; | |
LODWORD(v41) = v40 + v28; | |
v44 = this->pos; | |
if ( SHIDWORD(v41) >= v40 + v28 ) | |
v43 = v42; | |
this->maxOffset = v43; | |
this->pos = v44 + HIDWORD(intervals); | |
size %= transferSize; | |
} | |
v45 = size / burstSize; | |
if ( size / burstSize > 0 ) | |
{ | |
if ( v45 - 1 > 0 ) | |
{ | |
v46 = HIDWORD(intervals) * (v45 - 1); | |
v57 = v46 - HIDWORD(intervals); | |
if ( SHIDWORD(intervals) > 0 ) | |
v28 += v57; | |
else | |
v27 += v57; | |
} | |
else | |
{ | |
v46 = 0; | |
v27 = 0; | |
v28 = 0; | |
} | |
v47 = v46 + burstSize; | |
if ( v27 > v47 ) | |
v27 = v47; | |
v48 = this->pos; | |
if ( v28 < v47 ) | |
v28 = v47; | |
v49 = v48 + v27; | |
v50 = this->pos; | |
if ( this->minOffset < v48 + v27 ) | |
v49 = this->minOffset; | |
v51 = this->maxOffset; | |
v52 = v50 + v28; | |
this->minOffset = v49; | |
v53 = this->pos; | |
if ( v51 >= v50 + v28 ) | |
v52 = v51; | |
this->maxOffset = v52; | |
v54 = v53 + v47; | |
v19 = burstSize * (size / burstSize); | |
this->pos = v54; | |
LABEL_106: | |
size -= v19; | |
} | |
} | |
else | |
{ | |
v20 = size / burstSize; | |
if ( size / burstSize > 0 ) | |
{ | |
v21 = burstSize + HIDWORD(intervals); | |
this->maxOffset = burstSize; | |
this->pos = burstSize + HIDWORD(intervals); | |
if ( burstSize + HIDWORD(intervals) >= 0 ) | |
{ | |
if ( this->maxOffset >= v21 ) | |
v21 = this->maxOffset; | |
this->maxOffset = v21; | |
} | |
else | |
{ | |
this->minOffset = v21; | |
} | |
if ( v20 - 1 > 0 ) | |
{ | |
v22 = this->pos * (v20 - 1); | |
if ( this->pos > 0 ) | |
v23 = this->maxOffset; | |
else | |
v23 = this->minOffset; | |
v24 = v23 + v22 - this->pos; | |
if ( this->pos > 0 ) | |
this->maxOffset = v24; | |
else | |
this->minOffset = v24; | |
this->pos = v22; | |
} | |
else | |
{ | |
v22 = 0; | |
this->pos = 0; | |
this->minOffset = 0; | |
this->maxOffset = 0; | |
} | |
v25 = this->minOffset; | |
v26 = v22 + burstSize; | |
this->pos = v26; | |
if ( v26 >= v25 ) | |
{ | |
if ( this->maxOffset >= v26 ) | |
v26 = this->maxOffset; | |
this->maxOffset = v26; | |
} | |
else | |
{ | |
this->minOffset = v26; | |
} | |
size %= burstSize; | |
} | |
} | |
} | |
LABEL_107: | |
v55 = this->pos + size; | |
v9 = this->minOffset <= v55; | |
this->pos = v55; | |
if ( v9 ) | |
{ | |
if ( v55 <= this->maxOffset ) | |
v55 = this->maxOffset; | |
v56 = this; | |
this->maxOffset = v55; | |
} | |
else | |
{ | |
v56 = this; | |
this->minOffset = v55; | |
} | |
v56->pos = 0; | |
} | |
//----- (FFF1689C) -------------------------------------------------------- | |
bool __fastcall KDmaAddress::CheckPhysicalMemContiguous(KDmaAddress *this, s32 minOffset, s32 maxOffset) | |
{ | |
return KDmaAddress::GetPhysicalChunkSize(this, minOffset) == minOffset | |
&& KDmaAddress::GetPhysicalChunkSize(this, maxOffset) == maxOffset; | |
} | |
//----- (FFF168D8) -------------------------------------------------------- | |
Result __fastcall KPageTable::CheckMemoryBlockAttributes( | |
KPageTable *this, | |
u32 addr, | |
u32 size, | |
KMemoryState state, | |
KMemoryPermission perms) | |
{ | |
Result result; // r0 | |
u32 endAddr; // r1 | |
KMemoryInfo info; // [sp+0h] [bp-28h] BYREF | |
u32 pageInfo[6]; // [sp+10h] [bp-18h] BYREF | |
result = KPageTable::QueryInfo(this, &info, pageInfo, addr); | |
if ( result >= 0 ) | |
{ | |
result = 0xE0A01BF5; | |
if ( info.state == state && (perms & ~info.perms) == 0 ) | |
{ | |
endAddr = addr + size; | |
if ( (!size || addr <= endAddr - 1) && endAddr <= info.baseAddress + info.size ) | |
return 0; | |
} | |
} | |
return result; | |
} | |
//----- (FFF16958) -------------------------------------------------------- | |
Result __fastcall KPageTable::MapL2Entries( | |
KPageTable *this, | |
u32 va, | |
u32 pa, | |
u32 numPages_reused, | |
u32 *attribsPtr, | |
bool isLarge) | |
{ | |
_DWORD *p_lockingThread; // r9 | |
unsigned int v9; // r5 | |
u32 v10; // r0 | |
unsigned int v11; // r2 | |
KLevel2TranslationTable *rootNode; // r2 | |
char *Contiguous; // r11 | |
u32 v14; // r1 | |
unsigned int v15; // r2 | |
bool v16; // zf | |
unsigned int v17; // r2 | |
unsigned int v18; // r1 | |
unsigned int i; // r7 | |
KLevel2TranslationTable *v20; // r0 | |
KLevel2TranslationTable *v21; // r1 | |
u32 v22; // r0 | |
u32 v23; // r7 | |
u32 *v24; // r2 | |
u32 v25; // r3 | |
u32 *v26; // r1 | |
unsigned int j; // r2 | |
u32 k; // r10 | |
unsigned int *v29; // r0 | |
unsigned int v30; // r1 | |
bool v31; // zf | |
_DWORD *v32; // r8 | |
_WORD *v33; // r3 | |
u32 *v34; // r0 | |
u32 v35; // r1 | |
u32 v37; // [sp+4h] [bp-7Ch] | |
u32 v38; // [sp+14h] [bp-6Ch] | |
int v39; // [sp+2Ch] [bp-54h] | |
u32 v40; // [sp+34h] [bp-4Ch] | |
u32 v41; // [sp+38h] [bp-48h] | |
u32 v42; // [sp+3Ch] [bp-44h] | |
if ( isLarge ) | |
{ | |
v9 = 0x10000; | |
v10 = *attribsPtr & 0xE30 | 1 | *attribsPtr & 0xC | ((*attribsPtr & 1) << 15) | ((*attribsPtr & 0x1C0) << 6); | |
} | |
else | |
{ | |
v9 = 4096; | |
v10 = *attribsPtr | 2; | |
} | |
v37 = numPages_reused; | |
v40 = v10; | |
if ( numPages_reused ) | |
{ | |
while ( 1 ) | |
{ | |
v41 = va; | |
v38 = va >> 20; | |
v39 = 0; | |
if ( (this->L1Table[va >> 20] & 3) == 1 ) | |
{ | |
Contiguous = (char *)((this->L1Table[va >> 20] >> 10 << 10) - 0x40000000); | |
v42 = this->L1Table[va >> 20] >> 10 << 10; | |
goto LABEL_52; | |
} | |
v11 = __ldrex((unsigned int *)&g_level2TtblAllocator.mutex); | |
p_lockingThread = &g_level2TtblAllocator.mutex.lockingThread; | |
if ( v11 ) | |
break; | |
if ( __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_level2TtblAllocator.mutex) ) | |
goto LABEL_8; | |
LABEL_9: | |
__mcr(15, 0, 0, 7, 10, 5); | |
rootNode = g_level2TtblAllocator.rootNode; | |
if ( !g_level2TtblAllocator.rootNode ) | |
{ | |
v15 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v16 = v15 == 0; | |
if ( v15 ) | |
__strex(v15, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v15 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( v16 ) | |
v16 = v15 == 0; | |
if ( !v16 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
do | |
v17 = __ldrex(&g_memoryManager.pgMgr.kernelMemoryUsage); | |
while ( __strex(v17 + 4096, &g_memoryManager.pgMgr.kernelMemoryUsage) ); | |
Contiguous = (char *)KPageHeap::AllocateContiguous(&g_memoryManager.baseHeap, 1u, 0); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
if ( !Contiguous ) | |
{ | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_level2TtblAllocator.mutex.lockingThread = 0; | |
if ( g_level2TtblAllocator.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_level2TtblAllocator.mutex); | |
LABEL_50: | |
kernelpanic(); | |
} | |
v18 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( v18 ) | |
{ | |
__strex(v18, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
goto LABEL_33; | |
} | |
if ( __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex) ) | |
LABEL_33: | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)Contiguous, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
for ( i = 1; i < 4; ++i ) | |
{ | |
v20 = (KLevel2TranslationTable *)&Contiguous[1024 * i]; | |
if ( v20 ) | |
{ | |
v20->next = 0; | |
v20->prev = 0; | |
} | |
v21 = g_level2TtblAllocator.rootNode; | |
if ( g_level2TtblAllocator.rootNode ) | |
{ | |
v20->prev = g_level2TtblAllocator.rootNode; | |
v21->next->prev = v20; | |
v20->next = v21->next; | |
v21->next = v20; | |
} | |
else | |
{ | |
v20->prev = v20; | |
v20->next = v20; | |
} | |
g_level2TtblAllocator.rootNode = v20; | |
} | |
v14 = g_level2TtblAllocator.numAvailable + 3; | |
goto LABEL_44; | |
} | |
if ( g_level2TtblAllocator.rootNode->next == g_level2TtblAllocator.rootNode ) | |
{ | |
g_level2TtblAllocator.rootNode = 0; | |
} | |
else | |
{ | |
g_level2TtblAllocator.rootNode = g_level2TtblAllocator.rootNode->prev; | |
rootNode->prev->next = rootNode->next; | |
rootNode->next->prev = rootNode->prev; | |
} | |
rootNode->prev = 0; | |
rootNode->next = 0; | |
Contiguous = (char *)rootNode; | |
v14 = g_level2TtblAllocator.numAvailable - 1; | |
LABEL_44: | |
g_level2TtblAllocator.numAvailable = v14; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_level2TtblAllocator.mutex.lockingThread = 0; | |
if ( g_level2TtblAllocator.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_level2TtblAllocator.mutex); | |
if ( !Contiguous ) | |
goto LABEL_50; | |
memset(Contiguous, 0, 0x400u); | |
v39 = 1; | |
v42 = (u32)(Contiguous + 0x40000000); | |
LABEL_52: | |
v22 = (0x100000 - (va & 0xFFFFF)) >> 12; | |
if ( v22 > v37 ) | |
v22 = v37; | |
v23 = v22; | |
for ( v37 -= v22; v22; pa += v9 ) | |
{ | |
v24 = (u32 *)&Contiguous[(va & 0xFF000) >> 10]; | |
v25 = v40 | pa; | |
if ( v9 >> 12 ) | |
{ | |
v26 = v24 - 1; | |
if ( (v9 & 0x1000) != 0 ) | |
{ | |
*v24 = v25; | |
v26 = (u32 *)&Contiguous[(va & 0xFF000) >> 10]; | |
} | |
for ( j = v9 >> 13; j; v26 += 2 ) | |
{ | |
v26[1] = v25; | |
--j; | |
v26[2] = v25; | |
} | |
} | |
v22 -= v9 >> 12; | |
va += v9; | |
} | |
if ( v42 - 0x20000000 < 0x10000000 ) | |
{ | |
if ( v23 ) | |
p_lockingThread = &g_level2TtblAllocator; | |
for ( k = 0; k < v23; ++k ) | |
{ | |
v29 = p_lockingThread + 4; | |
v30 = __ldrex(p_lockingThread + 4); | |
v31 = v30 == 0; | |
v32 = p_lockingThread + 4; | |
if ( v30 ) | |
__strex(v30, v29); | |
else | |
v30 = __strex((unsigned int)current.clc.current.thread, v29); | |
if ( v31 ) | |
v31 = v30 == 0; | |
if ( !v31 ) | |
KLightMutex::LockImpl((KLightMutex *)v29); | |
__mcr(15, 0, 0, 7, 10, 5); | |
v33 = (_WORD *)(p_lockingThread[1] + 2 * ((unsigned int)&Contiguous[-p_lockingThread[2]] >> 10)); | |
++*v33; | |
__mcr(15, 0, 0, 7, 10, 5); | |
*v32 = 0; | |
if ( *((__int16 *)v32 + 2) > 0 ) | |
KLightMutex::UnlockImpl((KLightMutex *)p_lockingThread + 2); | |
} | |
} | |
if ( v39 ) | |
{ | |
KPageTable::CleanDataCacheRange((u32)Contiguous, 0x400u); | |
this->L1Table[v38] = (v42 >> 10 << 10) | 1; | |
v34 = &this->L1Table[v38]; | |
v35 = 4; | |
} | |
else | |
{ | |
v35 = 4 * v23; | |
v34 = (u32 *)&Contiguous[(v41 & 0xFF000) >> 10]; | |
} | |
KPageTable::CleanDataCacheRange((u32)v34, v35); | |
if ( !v37 ) | |
return 0; | |
} | |
__strex(v11, (unsigned int *)&g_level2TtblAllocator.mutex); | |
LABEL_8: | |
KLightMutex::LockImpl(&g_level2TtblAllocator.mutex); | |
goto LABEL_9; | |
} | |
return 0; | |
} | |
// FFF16B14: conditional instruction was optimized away because r0.4==300 | |
// FFF16B1C: conditional instruction was optimized away because r0.4==300 | |
// FFF16DB0: variable 'p_lockingThread' is possibly undefined | |
//----- (FFF16ECC) -------------------------------------------------------- | |
Result __fastcall KPageTable::MapL1Entries( | |
KPageTable *this, | |
u32 va, | |
u32 pa, | |
u32 numPages, | |
u32 *attribsPtr, | |
bool isLarge) | |
{ | |
u32 v6; // r11 | |
unsigned int v7; // r10 | |
u32 v8; // r12 | |
u32 v9; // r4 | |
u32 **p_L1Table; // r5 | |
u32 v11; // r6 | |
unsigned int v12; // r0 | |
int v13; // lr | |
u32 v14; // r8 | |
int v15; // lr | |
u32 v16; // r9 | |
u32 v19; // [sp+8h] [bp-40h] | |
unsigned int v20; // [sp+Ch] [bp-3Ch] | |
v6 = 0; | |
if ( isLarge ) | |
v7 = 0x1000000; | |
else | |
v7 = 0x100000; | |
v8 = *attribsPtr & 0xC; | |
if ( isLarge ) | |
v8 |= 0x40002u; | |
if ( !isLarge ) | |
v8 |= 2u; | |
v19 = v8 | ((*attribsPtr & 0xFF0) << 6) | (16 * (*attribsPtr & 1)); | |
if ( numPages ) | |
{ | |
v20 = v7 >> 20; | |
do | |
{ | |
v9 = va >> 20; | |
p_L1Table = &this->L1Table; | |
v11 = pa | v19; | |
if ( v20 ) | |
{ | |
v12 = (v7 & 0x100000) != 0; | |
v13 = 0; | |
if ( v12 == 1 ) | |
{ | |
v13 = 1; | |
(*p_L1Table)[v9] = v11; | |
} | |
for ( ; v12 < v20; (*p_L1Table)[v16] = v11 ) | |
{ | |
v14 = v9 + v13; | |
v15 = v13 + 1; | |
v16 = v9 + v15; | |
(*p_L1Table)[v14] = v11; | |
v12 += 2; | |
v13 = v15 + 1; | |
} | |
} | |
v6 += v7 >> 12; | |
pa += v7; | |
va += v7; | |
} | |
while ( v6 < numPages ); | |
} | |
KPageTable::CleanDataCacheRange((u32)&this->L1Table[va >> 20], 4 * (numPages >> 8)); | |
return 0; | |
} | |
//----- (FFF16FD8) -------------------------------------------------------- | |
Result __fastcall KPageTable::MergeContiguousEntries(KPageTable *this, u32 va) | |
{ | |
Result v4; // r3 | |
unsigned int L1Entry; // r1 | |
int L1EntryType; // r0 | |
u32 v7; // r5 | |
unsigned int v8; // r0 | |
int v9; // r1 | |
bool v10; // zf | |
unsigned int v11; // r4 | |
int v12; // r1 | |
int v13; // r8 | |
int v14; // r2 | |
u32 v15; // r0 | |
int v16; // r1 | |
unsigned int v17; // r9 | |
int v18; // r1 | |
__int16 v19; // r0 | |
unsigned int v20; // r2 | |
bool v21; // zf | |
unsigned int v22; // r3 | |
u32 v23; // r0 | |
unsigned int v24; // r2 | |
bool v25; // zf | |
unsigned int v26; // r3 | |
KLevel2TranslationTable *rootNode; // r2 | |
u32 v28; // r2 | |
unsigned int v29; // r12 | |
int v30; // r0 | |
__int16 v31; // r0 | |
unsigned int v32; // r3 | |
u32 v33; // r0 | |
int v34; // r2 | |
unsigned int i; // r1 | |
u32 v36; // r5 | |
int v37; // r2 | |
u32 v38; // r6 | |
int v40; // [sp+0h] [bp-28h] | |
v4 = 0xE0A01BF5; | |
if ( this->onlyUseSmallPages ) | |
return v4; | |
L1Entry = this->L1Table[va >> 20]; | |
L1EntryType = L1Entry & 0x40003; | |
if ( (L1Entry & 0x40003) != 1 ) | |
{ | |
if ( L1EntryType == 2 ) | |
{ | |
LABEL_48: | |
v28 = va & 0xFF000000; | |
v29 = L1Entry & 0xFF000000; | |
v30 = 0; | |
while ( ((v29 + (v30 << 20)) | L1Entry & 0xFFFFF) == this->L1Table[(v28 + (v30 << 20)) >> 20] ) | |
{ | |
if ( (unsigned int)++v30 >= 0x10 ) | |
{ | |
v31 = L1Entry & 0xC | ((unsigned __int16)(L1Entry & 0x7000) >> 6) | ((L1Entry & 0x38C00) >> 6) | ((unsigned __int8)(L1Entry & 0x10) >> 4); | |
v32 = v29 | v31 & 0xC | 0x40002 | ((((unsigned __int16)(L1Entry & 0x7000) >> 6) & 0xFF0 | ((L1Entry & 0x38C00) >> 6) & 0xFF0 | ((unsigned __int8)(L1Entry & 0x10) >> 4) & 0xF0) << 6) | (16 * (v31 & 1)); | |
v33 = v28 >> 20; | |
v34 = 0; | |
for ( i = 0; i < 0x10; i += 2 ) | |
{ | |
v36 = v33 + v34; | |
v37 = v34 + 1; | |
v38 = v33 + v37; | |
this->L1Table[v36] = v32; | |
v34 = v37 + 1; | |
this->L1Table[v38] = v32; | |
} | |
KPageTable::CleanDataCacheRange((u32)&this->L1Table[v33], 0x40u); | |
return 0; | |
} | |
} | |
return v4; | |
} | |
if ( L1EntryType != 262145 ) | |
return v4; | |
} | |
v7 = (L1Entry >> 10 << 10) + 0xC0000000; | |
v8 = *(_DWORD *)(v7 + ((va & 0xFF000) >> 10)); | |
v9 = v8 & 3; | |
if ( v9 == 1 ) | |
{ | |
LABEL_16: | |
va = va >> 20 << 20; | |
v17 = v8 >> 20 << 20; | |
v18 = 0; | |
while ( ((v17 + (v18 << 16)) | (unsigned __int16)v8) == *(_DWORD *)(v7 + (((va + (v18 << 16)) & 0xFF000) >> 10)) ) | |
{ | |
if ( (unsigned int)++v18 >= 0x10 ) | |
{ | |
v19 = v8 & 0xE3C | ((unsigned __int16)(v8 & 0x7000) >> 6) | ((unsigned __int16)(v8 & 0x8000) >> 15); | |
v40 = v19 & 0xC | 2 | ((v19 & 0xFF0) << 6) | (16 * (v19 & 1)); | |
this->L1Table[va >> 20] = v17 | v40; | |
KPageTable::CleanDataCacheRange((u32)&this->L1Table[va >> 20], 4u); | |
KPageTable::InvalidateAllTlbEntries(this); | |
if ( v7 + 0x20000000 < 0x10000000 ) | |
{ | |
while ( 1 ) | |
{ | |
v20 = __ldrex((unsigned int *)&g_level2TtblAllocator.mutex); | |
v21 = v20 == 0; | |
if ( v20 ) | |
v22 = __strex(v20, (unsigned int *)&g_level2TtblAllocator.mutex); | |
else | |
v22 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_level2TtblAllocator.mutex); | |
if ( !v20 ) | |
v21 = v22 == 0; | |
if ( !v21 ) | |
KLightMutex::LockImpl(&g_level2TtblAllocator.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
v23 = (v7 - g_level2TtblAllocator.baseRegionStart) >> 10; | |
if ( !--g_level2TtblAllocator.refcounts[v23] ) | |
break; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_level2TtblAllocator.mutex.lockingThread = 0; | |
if ( g_level2TtblAllocator.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_level2TtblAllocator.mutex); | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_level2TtblAllocator.mutex.lockingThread = 0; | |
if ( g_level2TtblAllocator.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_level2TtblAllocator.mutex); | |
v24 = __ldrex((unsigned int *)&g_level2TtblAllocator.mutex); | |
v25 = v24 == 0; | |
if ( v24 ) | |
v26 = __strex(v24, (unsigned int *)&g_level2TtblAllocator.mutex); | |
else | |
v26 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_level2TtblAllocator.mutex); | |
if ( !v24 ) | |
v25 = v26 == 0; | |
if ( !v25 ) | |
KLightMutex::LockImpl(&g_level2TtblAllocator.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( v7 ) | |
{ | |
*(_DWORD *)v7 = 0; | |
*(_DWORD *)(v7 + 4) = 0; | |
} | |
rootNode = g_level2TtblAllocator.rootNode; | |
if ( g_level2TtblAllocator.rootNode ) | |
{ | |
*(_DWORD *)(v7 + 4) = g_level2TtblAllocator.rootNode; | |
rootNode->next->prev = (KLevel2TranslationTable *)v7; | |
*(_DWORD *)v7 = rootNode->next; | |
rootNode->next = (KLevel2TranslationTable *)v7; | |
} | |
else | |
{ | |
*(_DWORD *)(v7 + 4) = v7; | |
*(_DWORD *)v7 = v7; | |
} | |
g_level2TtblAllocator.rootNode = (KLevel2TranslationTable *)v7; | |
++g_level2TtblAllocator.numAvailable; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_level2TtblAllocator.mutex.lockingThread = 0; | |
if ( g_level2TtblAllocator.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_level2TtblAllocator.mutex); | |
} | |
v4 = 0; | |
L1Entry = v17 | v40; | |
goto LABEL_48; | |
} | |
} | |
} | |
else | |
{ | |
v10 = v9 == 2; | |
if ( v9 != 2 ) | |
v10 = v9 == 3; | |
if ( v10 ) | |
{ | |
va = HIWORD(va) << 16; | |
v11 = HIWORD(v8) << 16; | |
v12 = 0; | |
while ( ((v11 + (v12 << 12)) | v8 & 0xFFF) == *(_DWORD *)(v7 + (((va + (v12 << 12)) & 0xFF000) >> 10)) ) | |
{ | |
if ( (unsigned int)++v12 >= 0x10 ) | |
{ | |
v13 = v8 & 0xC | v8 & 0xE30 | 1 | ((v8 & 1) << 15) | ((v8 & 0x1C0) << 6); | |
v14 = v11 | v13; | |
v15 = v7 + ((va & 0xFF000) >> 10) - 4; | |
v16 = 8; | |
do | |
{ | |
*(_DWORD *)(v15 + 4) = v14; | |
--v16; | |
*(_DWORD *)(v15 + 8) = v14; | |
v15 += 8; | |
} | |
while ( v16 ); | |
KPageTable::CleanDataCacheRange(v7 + ((va & 0xFF000) >> 10), 0x40u); | |
v8 = v11 | v13; | |
v4 = 0; | |
goto LABEL_16; | |
} | |
} | |
} | |
} | |
return v4; | |
} | |
/* Orphan comments: | |
can't merge if we only use small pages | |
{points at temple} | |
*/ | |
//----- (FFF173D0) -------------------------------------------------------- | |
Result __fastcall KPageTable::MapContiguousPhysicalAddressRange( | |
KPageTable *this, | |
u32 va, | |
u32 pa, | |
u32 numPages, | |
u32 *mmuAttribs) | |
{ | |
u32 v5; // r5 | |
u32 v6; // r7 | |
u32 v9; // r4 | |
unsigned int i; // r6 | |
Result result; // r0 | |
unsigned int v12; // r10 | |
unsigned int v13; // r2 | |
unsigned int v14; // r3 | |
Result v15; // r0 | |
int v16; // r10 | |
Result v17; // r0 | |
unsigned int v18; // r2 | |
bool v19; // zf | |
u32 *attribsPtr; // [sp+0h] [bp-38h] | |
v5 = va; | |
v6 = pa; | |
v9 = numPages; | |
if ( this->onlyUseSmallPages || numPages < 0x10 ) | |
{ | |
result = KPageTable::MapL2Entries(this, va, pa, numPages, mmuAttribs, 0); | |
if ( result < 0 ) | |
return result; | |
} | |
else | |
{ | |
for ( i = 0x10000; i <= 0x1000000; i *= 16 ) | |
{ | |
if ( (v5 & (i - 1)) != (v6 & (i - 1)) ) | |
break; | |
v12 = ((i - 1) & (i - v5)) >> 12; | |
if ( v12 + (i >> 12) > v9 ) | |
break; | |
if ( v12 ) | |
{ | |
v13 = i >> 4; | |
v14 = ((i - 1) & (i - v5)) >> 12; | |
if ( i >> 4 == 4096 ) | |
{ | |
v15 = KPageTable::MapL2Entries(this, v5, v6, v14, mmuAttribs, 0); | |
} | |
else | |
{ | |
switch ( v13 ) | |
{ | |
case 0x10000u: | |
v15 = KPageTable::MapL2Entries(this, v5, v6, v14, mmuAttribs, 1); | |
break; | |
case 0x100000u: | |
v15 = KPageTable::MapL1Entries(this, v5, v6, v14, mmuAttribs, 0); | |
break; | |
case 0x1000000u: | |
v15 = KPageTable::MapL1Entries(this, v5, v6, v14, mmuAttribs, 1); | |
break; | |
default: | |
v15 = -656406531; | |
break; | |
} | |
} | |
attribsPtr = (u32 *)v15; | |
if ( v15 < 0 ) | |
{ | |
LABEL_28: | |
if ( numPages != v9 ) | |
KPageTable::UnmapEntries(this, va, numPages - v9, 0); | |
return (Result)attribsPtr; | |
} | |
v9 -= v12; | |
v5 += v12 << 12; | |
v6 += v12 << 12; | |
} | |
} | |
while ( 1 ) | |
{ | |
i >>= 4; | |
if ( !v9 || i < 0x1000 ) | |
break; | |
v16 = v9 & ~((i >> 12) - 1); | |
if ( v16 ) | |
{ | |
switch ( i ) | |
{ | |
case 0x1000u: | |
v17 = KPageTable::MapL2Entries(this, v5, v6, v16, mmuAttribs, 0); | |
break; | |
case 0x10000u: | |
v17 = KPageTable::MapL2Entries(this, v5, v6, v16, mmuAttribs, 1); | |
break; | |
case 0x100000u: | |
v17 = KPageTable::MapL1Entries(this, v5, v6, v16, mmuAttribs, 0); | |
break; | |
case 0x1000000u: | |
v17 = KPageTable::MapL1Entries(this, v5, v6, v9 & 0xFFFFF000, mmuAttribs, 1); | |
break; | |
default: | |
v17 = -656406531; | |
break; | |
} | |
attribsPtr = (u32 *)v17; | |
if ( v17 < 0 ) | |
goto LABEL_28; | |
v9 -= v16; | |
v5 += v16 << 12; | |
v6 += v16 << 12; | |
} | |
} | |
} | |
KPageTable::MergeContiguousEntries(this, va); | |
if ( numPages > 1 ) | |
KPageTable::MergeContiguousEntries(this, va + (numPages << 12) - 4096); | |
if ( pa - 0x20000000 < 0x10000000 ) | |
{ | |
v18 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v19 = v18 == 0; | |
if ( v18 ) | |
__strex(v18, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v18 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( v19 ) | |
v19 = v18 == 0; | |
if ( !v19 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, pa - 0x40000000, numPages); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
} | |
return 0; | |
} | |
//----- (FFF17718) -------------------------------------------------------- | |
KPageHeapBlock *__fastcall KPageHeap::AllocateBackwards(KPageHeap *this, u32 size) | |
{ | |
KPageHeapBlock *curBlkRev; // r4 | |
KPageHeapBlock *next; // r0 | |
bool v5; // zf | |
u32 remaining; // r5 | |
KPageHeapBlock *v7; // r8 | |
u32 regionSize; // r0 | |
u32 numPages; // r6 | |
u32 v10; // r8 | |
KPageHeapBlock *v11; // r6 | |
KPageHeapBlock *prev; // r4 | |
KPageHeapBlock *i; // r4 | |
next = this->link.next; | |
v5 = next == 0; | |
if ( next ) | |
{ | |
curBlkRev = this->link.prev; | |
v5 = curBlkRev == 0; | |
} | |
if ( !v5 && size ) | |
{ | |
remaining = size; | |
v7 = 0; | |
do | |
{ | |
KPageHeap::ValidateBlock(this, curBlkRev); | |
regionSize = this->regionSize; | |
numPages = curBlkRev->numPages; | |
if ( curBlkRev->numPages > regionSize >> 12 | |
|| regionSize + this->regionStart < (unsigned int)curBlkRev + 4096 * numPages ) | |
{ | |
kernelpanic(); | |
} | |
if ( curBlkRev->link.next != v7 ) | |
kernelpanic(); | |
if ( numPages >= remaining ) | |
{ | |
v10 = numPages - remaining; | |
v11 = KPageHeap::SplitBlock(this, curBlkRev, numPages - remaining); | |
if ( v11 ) | |
{ | |
if ( curBlkRev->numPages != v10 ) | |
kernelpanic(); | |
} | |
else | |
{ | |
v11 = curBlkRev; | |
} | |
prev = v11->link.prev; | |
KPageHeap::ValidateBlock(this, prev); | |
KPageHeap::SetLastBlock(this, prev); | |
v11->link.prev = 0; | |
KPageHeap::UpdateBlockMac(this, v11); | |
if ( v11->numPages != remaining ) | |
kernelpanic(); | |
return v11; | |
} | |
v7 = curBlkRev; | |
curBlkRev = curBlkRev->link.prev; | |
remaining -= numPages; | |
} | |
while ( curBlkRev ); | |
for ( i = this->link.next; i; i = i->link.next ) | |
KPageHeap::ValidateBlock(this, i); | |
} | |
return 0; | |
} | |
// FFF1774C: variable 'curBlkRev' is possibly undefined | |
//----- (FFF17844) -------------------------------------------------------- | |
Result __fastcall KMemoryBlockManager::MutateRange( | |
KMemoryBlockManager *this, | |
u32 va, | |
u32 numPages, | |
KMemoryState state, | |
KMemoryPermission perms, | |
u32 tag) | |
{ | |
KMemoryBlockLinkedListNode *next; // r0 | |
int numBlocks; // r9 | |
KMemoryBlockLinkedListNode *it2; // r0 | |
KMemoryBlockLinkedListNode *v13; // r0 | |
KMemoryBlock *block; // r9 | |
KMemoryBlockLinkedListNode *v15; // r11 | |
KMemoryBlockLinkedListNode *v16; // r0 | |
KMemoryBlockLinkedListNode *v17; // r10 | |
KMemoryBlock *v18; // r3 | |
KMemoryPermission v19; // r1 | |
bool v20; // zf | |
KMemoryBlockLinkedListNode *v21; // r5 | |
KMemoryBlock *v22; // r0 | |
KMemoryBlock *v23; // r6 | |
KMemoryBlock *v24; // r1 | |
KMemoryPermission v25; // r2 | |
bool v26; // zf | |
KMemoryBlock *v27; // r0 | |
KMemoryBlock *v28; // r9 | |
KLinkedListNode *v29; // r0 | |
u32 v30; // r10 | |
KMemoryBlock *v31; // r9 | |
KLinkedListNode *v32; // r0 | |
KMemoryBlockLinkedListNode *v33; // r0 | |
KMemoryBlock *v34; // r5 | |
KMemoryState v35; // r1 | |
u32 baseAddress; // r2 | |
KLinkedListNode *v37; // r0 | |
KMemoryBlock *v38; // r0 | |
KMemoryPermission v39; // r2 | |
bool v40; // zf | |
KMemoryBlockLinkedListNode *v41; // r6 | |
KMemoryBlock *v42; // r5 | |
KMemoryBlockLinkedListNode *v43; // r11 | |
KMemoryBlock *v44; // r9 | |
KMemoryBlockLinkedListNode *v45; // r0 | |
KMemoryBlockLinkedListNode *v46; // r10 | |
KMemoryBlockLinkedListNode *v47; // r11 | |
KMemoryBlock *v48; // r9 | |
KMemoryBlockLinkedListNode *v49; // r0 | |
KMemoryBlockLinkedListNode *v50; // r10 | |
KMemoryBlock *v51; // r9 | |
KLinkedListNode *v52; // r0 | |
KMemoryBlockLinkedListNode *nodeContainingVa; // [sp+0h] [bp-68h] BYREF | |
KMemoryBlockLinkedListNode *blockContainingVaNode; // [sp+10h] [bp-58h] BYREF | |
KMemoryInfo result; // [sp+20h] [bp-48h] BYREF | |
u32 endVa; // [sp+38h] [bp-30h] | |
KMemoryBlockLinkedListNode *blockContainingEndVaNode; // [sp+3Ch] [bp-2Ch] BYREF | |
endVa = va + (numPages << 12) - 1; | |
blockContainingEndVaNode = 0; | |
next = this->blocks.link.next; | |
numBlocks = 0; | |
while ( 1 ) | |
{ | |
blockContainingVaNode = next; | |
if ( next == (KMemoryBlockLinkedListNode *)&this->blocks.link || KMemoryBlock::Contains(next->block, va) ) | |
break; | |
next = blockContainingVaNode->link.next; | |
} | |
for ( it2 = blockContainingVaNode; ; it2 = blockContainingEndVaNode->link.next ) | |
{ | |
blockContainingEndVaNode = it2; | |
if ( it2 == (KMemoryBlockLinkedListNode *)&this->blocks.link ) | |
break; | |
++numBlocks; | |
if ( KMemoryBlock::Contains(it2->block, endVa) ) | |
break; | |
} | |
if ( numBlocks != 1 ) | |
{ | |
if ( numBlocks > 2 ) | |
{ // erase nodes | |
nodeContainingVa = blockContainingVaNode; | |
v13 = blockContainingVaNode->link.next; | |
for ( nodeContainingVa = v13; nodeContainingVa != blockContainingEndVaNode; v13 = nodeContainingVa ) | |
{ | |
block = v13->block; | |
v15 = v13; | |
KLinkedList::EraseNode((KLinkedList *)this, (KLinkedListLink **)&nodeContainingVa); | |
v17 = v16; | |
KSlabHeap::Free(&g_linkedListNodeSlabHeap, v15); | |
nodeContainingVa = v17; | |
KSlabHeap::Free(&g_memoryBlockSlabHeap, block); | |
} | |
} | |
v18 = blockContainingVaNode->block; | |
v19 = v18->perms; | |
v20 = v19 == perms; | |
if ( v19 == perms ) | |
v20 = v18->state == state; | |
if ( v20 ) | |
v20 = v18->tag == tag; | |
if ( v20 ) | |
{ | |
KMemoryBlock::GrowBlock(blockContainingVaNode->block, va, numPages); | |
v21 = blockContainingEndVaNode; | |
v22 = blockContainingEndVaNode->block; | |
if ( v22->baseAddr + (v22->numPages << 12) - 1 == endVa ) | |
{ | |
v23 = blockContainingEndVaNode->block; | |
KLinkedList::EraseNode((KLinkedList *)this, (KLinkedListLink **)&blockContainingEndVaNode); | |
KSlabHeap::Free(&g_linkedListNodeSlabHeap, v21); | |
KSlabHeap::Free(&g_memoryBlockSlabHeap, v23); | |
goto coalesce; | |
} | |
} | |
else | |
{ // not same/mergeable, delete and recreate or insert new | |
v38 = blockContainingEndVaNode->block; | |
v39 = v38->perms; | |
v40 = v39 == perms; | |
if ( v39 == perms ) | |
v40 = v38->state == state; | |
if ( v40 ) | |
v40 = v38->tag == tag; | |
if ( !v40 ) | |
{ | |
if ( KMemoryBlock::IncludesRange(blockContainingVaNode->block, va, numPages) ) | |
{ | |
v43 = blockContainingVaNode; | |
v44 = blockContainingVaNode->block; | |
KLinkedList::EraseNode((KLinkedList *)this, (KLinkedListLink **)&blockContainingVaNode); | |
v46 = v45; | |
KSlabHeap::Free(&g_linkedListNodeSlabHeap, v43); | |
blockContainingVaNode = v46; | |
KSlabHeap::Free(&g_memoryBlockSlabHeap, v44); | |
blockContainingVaNode = blockContainingVaNode->link.prev; | |
} | |
else | |
{ | |
KMemoryBlock::ShrinkBlock(blockContainingVaNode->block, va, numPages); | |
} | |
if ( KMemoryBlock::IncludesRange(blockContainingEndVaNode->block, va, numPages) ) | |
{ | |
v47 = blockContainingEndVaNode; | |
v48 = blockContainingEndVaNode->block; | |
KLinkedList::EraseNode((KLinkedList *)this, (KLinkedListLink **)&blockContainingEndVaNode); | |
v50 = v49; | |
KSlabHeap::Free(&g_linkedListNodeSlabHeap, v47); | |
blockContainingEndVaNode = v50; | |
KSlabHeap::Free(&g_memoryBlockSlabHeap, v48); | |
} | |
else | |
{ | |
KMemoryBlock::ShrinkBlock(blockContainingEndVaNode->block, va, numPages); | |
} | |
v51 = (KMemoryBlock *)KSlabHeap::Allocate(&g_memoryBlockSlabHeap); | |
v51->tag = 0; | |
v51->state = state; | |
v51->perms = perms; | |
v51->baseAddr = va; | |
v51->numPages = numPages; | |
v52 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v52 ) | |
{ | |
v52->link.next = 0; | |
v52->link.prev = 0; | |
v52->data = 0; | |
} | |
v52->data = v51; | |
KLinkedList::InsertAfter((KLinkedList *)this, (KLinkedListLink *)blockContainingEndVaNode, v52); | |
goto coalesce; | |
} | |
KMemoryBlock::GrowBlock(v38, va, numPages);// grow block containing end va | |
v41 = blockContainingVaNode; | |
v22 = blockContainingVaNode->block; // etc. | |
if ( v22->baseAddr == va ) | |
{ | |
v42 = blockContainingVaNode->block; | |
KLinkedList::EraseNode((KLinkedList *)this, (KLinkedListLink **)&blockContainingVaNode); | |
KSlabHeap::Free(&g_linkedListNodeSlabHeap, v41); | |
KSlabHeap::Free(&g_memoryBlockSlabHeap, v42); | |
goto coalesce; | |
} | |
} | |
KMemoryBlock::ShrinkBlock(v22, va, numPages);// shrink the block containing the start va | |
goto coalesce; | |
} | |
v24 = blockContainingVaNode->block; // else if (numBlocks == 1) | |
v25 = v24->perms; | |
v26 = v25 == perms; | |
if ( v25 == perms ) | |
v26 = v24->state == state; | |
if ( !v26 || v24->tag != tag ) | |
{ | |
KMemoryBlock::GetInfo(&result, v24); | |
if ( result.baseAddress == va ) | |
{ | |
v27 = blockContainingVaNode->block; | |
if ( result.size == numPages << 12 ) | |
{ | |
v27->tag = tag; | |
v27->state = state; | |
v27->perms = perms; | |
v27->baseAddr = va; | |
v27->numPages = numPages; | |
goto coalesce; | |
} | |
KMemoryBlock::ShrinkBlock(v27, va, numPages); | |
v28 = (KMemoryBlock *)KSlabHeap::Allocate(&g_memoryBlockSlabHeap); | |
v28->tag = tag; | |
v28->state = state; | |
v28->perms = perms; | |
v28->baseAddr = va; | |
v28->numPages = numPages; | |
v29 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v29 ) | |
{ | |
v29->link.next = 0; | |
v29->link.prev = 0; | |
v29->data = 0; | |
} | |
LABEL_30: | |
v29->data = v28; | |
KLinkedList::InsertAfter((KLinkedList *)this, (KLinkedListLink *)blockContainingVaNode, v29); | |
goto coalesce; | |
} | |
if ( result.baseAddress + result.size == endVa + 1 )// same end address, different base addr | |
{ | |
KMemoryBlock::ShrinkBlock(blockContainingVaNode->block, va, numPages); | |
blockContainingVaNode = blockContainingVaNode->link.next; | |
v28 = (KMemoryBlock *)KSlabHeap::Allocate(&g_memoryBlockSlabHeap); | |
v28->tag = tag; | |
v28->state = state; | |
v28->perms = perms; | |
v28->baseAddr = va; | |
v28->numPages = numPages; | |
v29 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v29 ) | |
{ | |
v29->link.next = 0; | |
v29->link.prev = 0; | |
v29->data = 0; | |
} | |
goto LABEL_30; | |
} | |
v30 = (va - result.baseAddress) >> 12; | |
KMemoryBlock::ShrinkBlock(blockContainingVaNode->block, 0, numPages + (va >> 12)); | |
v31 = (KMemoryBlock *)KSlabHeap::Allocate(&g_memoryBlockSlabHeap); | |
v31->tag = tag; | |
v31->state = state; | |
v31->perms = perms; | |
v31->baseAddr = va; | |
v31->numPages = numPages; | |
v32 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v32 ) | |
{ | |
v32->link.next = 0; | |
v32->link.prev = 0; | |
v32->data = 0; | |
} | |
v32->data = v31; | |
KLinkedList::InsertAfter((KLinkedList *)this, (KLinkedListLink *)blockContainingVaNode, v32); | |
blockContainingVaNode = v33; | |
v34 = (KMemoryBlock *)KSlabHeap::Allocate(&g_memoryBlockSlabHeap); | |
v35 = result.state; | |
baseAddress = result.baseAddress; | |
v34->perms = result.perms; | |
v34->state = v35; | |
v34->tag = 0; | |
v34->baseAddr = baseAddress; | |
v34->numPages = v30; | |
v37 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v37 ) | |
{ | |
v37->link.next = 0; | |
v37->link.prev = 0; | |
v37->data = 0; | |
} | |
v37->data = v34; | |
KLinkedList::InsertAfter((KLinkedList *)this, (KLinkedListLink *)blockContainingVaNode, v37); | |
} | |
coalesce: | |
KMemoryBlockManager::CoalesceBlocks(this); | |
return 0; | |
} | |
// FFF17AD0: conditional instruction was optimized away because r0.4!=0 | |
// FFF17B9C: conditional instruction was optimized away because r0.4!=0 | |
// FFF17C50: conditional instruction was optimized away because r0.4!=0 | |
// FFF17CE0: conditional instruction was optimized away because r0.4!=0 | |
// FFF17EF0: conditional instruction was optimized away because r0.4!=0 | |
// FFF17938: variable 'v16' is possibly undefined | |
// FFF17C78: variable 'v33' is possibly undefined | |
// FFF17DD4: variable 'v45' is possibly undefined | |
// FFF17E54: variable 'v49' is possibly undefined | |
//----- (FFF17F34) -------------------------------------------------------- | |
void __fastcall KInterruptController::DisableInterrupt(u32 irqId) | |
{ | |
MPCORE.gicd.icenabler[(int)irqId / 32] = 1 << ((int)irqId % 32); | |
} | |
//----- (FFF17F64) -------------------------------------------------------- | |
void __fastcall KMemoryBlock::ShrinkBlock(KMemoryBlock *this, u32 va, u32 numPages) | |
{ | |
u32 baseAddr; // r12 | |
u32 endAddr; // r3 | |
bool v5; // cf | |
u32 v6; // r2 | |
bool v7; // cf | |
baseAddr = this->baseAddr; | |
endAddr = va + (numPages << 12) - 1; | |
v5 = this->baseAddr >= endAddr; | |
v6 = this->baseAddr + (this->numPages << 12) - 1; | |
if ( this->baseAddr < endAddr ) | |
v5 = endAddr >= v6; | |
if ( v5 ) | |
{ | |
v7 = baseAddr >= va; | |
if ( baseAddr < va ) | |
v7 = va >= v6; | |
if ( !v7 ) | |
this->numPages = (va - baseAddr) >> 12; | |
} | |
else | |
{ | |
this->baseAddr = endAddr + 1; | |
this->numPages = (v6 - endAddr) >> 12; | |
} | |
} | |
//----- (FFF17FCC) -------------------------------------------------------- | |
Result __fastcall KInterruptManager::UnbindKernelInterruptForCore(KInterruptManager *this, s32 irqId, s32 coreId) | |
{ | |
KLightMutex *p_mutex; // r0 | |
KLightMutex *v7; // r4 | |
unsigned int v8; // r2 | |
bool v9; // zf | |
unsigned int v10; // r3 | |
KInterruptEntry *v11; // r7 | |
Result v12; // r6 | |
KLightMutex *v13; // r0 | |
p_mutex = &this->mutex; | |
v7 = p_mutex; | |
v8 = __ldrex((unsigned int *)p_mutex); | |
v9 = v8 == 0; | |
if ( v8 ) | |
v10 = __strex(v8, (unsigned int *)p_mutex); | |
else | |
v10 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)p_mutex); | |
if ( !v8 ) | |
v9 = v10 == 0; | |
if ( !v9 ) | |
KLightMutex::LockImpl(p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( (unsigned int)irqId > 0x1F ) | |
{ | |
if ( (unsigned int)(irqId - 32) > 0x5F ) | |
{ | |
v12 = 0xD8E007FD; | |
v13 = v7; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v7->lockingThread = 0; | |
if ( v7->numWaiters <= 0 ) | |
return v12; | |
} | |
else | |
{ | |
KInterruptController::DisableInterrupt(irqId); | |
this->privateInterrupts[3][irqId].handler = 0;// global interrupt[irqId - 32] | |
v12 = 0; | |
v13 = v7; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v7->lockingThread = 0; | |
if ( v7->numWaiters <= 0 ) | |
return v12; | |
} | |
goto LABEL_13; | |
} | |
v11 = &this->privateInterrupts[coreId][irqId]; | |
if ( v11->handler ) | |
{ | |
KInterruptController::DisablePeripheralInterrupt(irqId); | |
v12 = 0; | |
v11->handler = 0; | |
} | |
else | |
{ | |
v12 = 0xD9600602; | |
} | |
v13 = v7; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v7->lockingThread = 0; | |
if ( v7->numWaiters > 0 ) | |
LABEL_13: | |
KLightMutex::UnlockImpl(v13); | |
return v12; | |
} | |
//----- (FFF180DC) -------------------------------------------------------- | |
Result __fastcall KInterruptManager::BindInterrupt( | |
KInterruptManager *this, | |
KInterruptHandler *handler, | |
u32 irqId, | |
s32 coreId, | |
s32 priority, | |
bool autoDisable, | |
bool levelSensitive) | |
{ | |
KLightMutex *p_mutex; // r0 | |
KLightMutex *v11; // r4 | |
unsigned int v12; // r2 | |
bool v13; // zf | |
unsigned int v14; // r3 | |
KInterruptEntry *v15; // r1 | |
Result v16; // r6 | |
KLightMutex *v17; // r0 | |
p_mutex = &this->mutex; | |
v11 = p_mutex; | |
v12 = __ldrex((unsigned int *)p_mutex); | |
v13 = v12 == 0; | |
if ( v12 ) | |
v14 = __strex(v12, (unsigned int *)p_mutex); | |
else | |
v14 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)p_mutex); | |
if ( !v12 ) | |
v13 = v14 == 0; | |
if ( !v13 ) | |
KLightMutex::LockImpl(p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( irqId > 0x1F ) | |
{ | |
if ( irqId - 32 <= 0x5F ) | |
{ | |
v16 = KInterruptManager::BindSharedInterrupt(this, handler, irqId, coreId, priority, autoDisable, levelSensitive); | |
v17 = v11; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v11->lockingThread = 0; | |
if ( v11->numWaiters <= 0 ) | |
return v16; | |
goto LABEL_15; | |
} | |
v16 = 0xD8E007FD; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v11->lockingThread = 0; | |
if ( v11->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v11); | |
} | |
else | |
{ | |
v15 = &this->privateInterrupts[coreId][irqId]; | |
if ( (unsigned int)priority < 0xF ) | |
{ | |
if ( v15->handler ) | |
{ | |
v16 = 0xD8E007F0; | |
} | |
else | |
{ | |
v15->autoDisable_ManualClear = autoDisable; | |
v15->disabled = 0; | |
v15->priority = priority; | |
v15->handler = handler; | |
KInterruptController::ClearInterruptPendingStatus(irqId); | |
KInterruptController::EnableWithPriority(irqId, priority); | |
v16 = 0; | |
} | |
} | |
else | |
{ | |
v16 = 0xD8E007FD; | |
} | |
v17 = v11; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v11->lockingThread = 0; | |
if ( v11->numWaiters > 0 ) | |
LABEL_15: | |
KLightMutex::UnlockImpl(v17); | |
} | |
return v16; | |
} | |
//----- (FFF18228) -------------------------------------------------------- | |
Result __fastcall KDebug::DispatchEvent(KDebug *this, DebugEventType type, u32 param1, u32 param2) | |
{ | |
KThread *currentThread; // r2 | |
KDebugThread *currentDebugThread; // r0 | |
KDebugThread *debugThread; // r0 | |
bool v11; // zf | |
int v12; // r1 | |
bool v13; // zf | |
u32 debugFlags; // r1 | |
bool v15; // zf | |
bool v16; // zf | |
KThread *volatile thread; // r8 | |
u32 userDebuggerCoreId; // r1 | |
Result result; // r0 | |
Result v20; // r7 | |
KThread *volatile v21; // r0 | |
unsigned int numExceptionEvents; // r0 | |
int v23; // r0 | |
bool v24; // zf | |
Result v25; // r6 | |
u32 v26; // r1 | |
currentThread = current.clc.current.thread; | |
currentDebugThread = current.clc.current.thread->debugThread; | |
if ( currentDebugThread ) | |
{ | |
switch ( type ) | |
{ | |
case DBGEVENT_ATTACH_PROCESS: | |
case DBGEVENT_ATTACH_THREAD: | |
case DBGEVENT_EXIT_THREAD: | |
case DBGEVENT_EXIT_PROCESS: | |
case DBGEVENT_EXCEPTION: | |
case DBGEVENT_OUTPUT_STRING: | |
if ( currentDebugThread->debugPauseRequested )// this can deref nullptr when the KDebug is being destroyed/detached! | |
// (use rosalina's "kill" gdbstub command and see for yourself) | |
{ | |
currentDebugThread->debugPauseRequested = 0; | |
KThread::SetDebugPauseState(currentThread, 1);// pause | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
switch ( type ) | |
{ | |
case DBGEVENT_ATTACH_PROCESS: | |
if ( this->processAttached ) | |
return 0; | |
goto LABEL_31; | |
case DBGEVENT_ATTACH_THREAD: | |
debugThread = current.clc.current.thread->debugThread; | |
v11 = debugThread == 0; | |
if ( debugThread ) | |
v11 = !debugThread->attached; | |
if ( !v11 ) | |
return 0; | |
goto LABEL_31; | |
case DBGEVENT_SCHEDULE_IN: | |
if ( (this->debugFlags & DBG_SIGNAL_SCHEDULE_EVENTS) != 0 ) | |
{ | |
v12 = current.clc.current.thread->schedulingMask & 0xF; | |
v13 = v12 == KTHREADSCHEDSTAT_TERMINATED; | |
if ( v12 != KTHREADSCHEDSTAT_TERMINATED ) | |
v13 = current.clc.current.thread->debugThread == 0; | |
if ( !v13 ) | |
goto label_scheduleInOut; | |
} | |
return 0; | |
case DBGEVENT_SCHEDULE_OUT: | |
debugFlags = this->debugFlags; | |
v15 = (debugFlags & DBG_SIGNAL_SCHEDULE_EVENTS) == 0; | |
if ( (debugFlags & DBG_SIGNAL_SCHEDULE_EVENTS) != 0 ) | |
{ | |
debugFlags = (u32)current.clc.current.thread->debugThread; | |
v15 = debugFlags == 0; | |
} | |
if ( !v15 | |
&& !*(_BYTE *)(debugFlags + 7) // scheduledOut | |
&& (current.clc.current.thread->schedulingMask & 0xF) != KTHREADSCHEDSTAT_TERMINATED ) | |
{ | |
goto label_scheduleInOut; | |
} | |
return 0; | |
case DBGEVENT_SYSCALL_IN: | |
if ( current.clc.current.thread->debugThread | |
&& (current.clc.current.thread->schedulingMask & 0xF) != KTHREADSCHEDSTAT_TERMINATED | |
&& (this->debugFlags & DBG_SIGNAL_SYSCALL_EVENTS) != 0 ) | |
{ | |
goto LABEL_31; | |
} | |
return 0; | |
case DBGEVENT_SYSCALL_OUT: | |
if ( (this->debugFlags & DBG_SIGNAL_SYSCALL_EVENTS) != 0 | |
&& (current.clc.current.thread->schedulingMask & 0xF) != KTHREADSCHEDSTAT_TERMINATED ) | |
{ | |
goto LABEL_31; | |
} | |
return 0; | |
case DBGEVENT_MAP: | |
if ( (this->debugFlags & 0x10) != 0 ) | |
goto LABEL_31; | |
return 0; | |
default: | |
v16 = type == DBGEVENT_SCHEDULE_OUT; | |
if ( type != DBGEVENT_SCHEDULE_OUT ) | |
v16 = type == DBGEVENT_SCHEDULE_IN; | |
if ( v16 ) | |
{ | |
label_scheduleInOut: | |
thread = current.clc.current.thread; | |
if ( type == DBGEVENT_SCHEDULE_IN ) | |
{ | |
v20 = KDebug::EmplaceAysncEventInfo(this, DBGEVENT_SCHEDULE_IN, 0, 0, 0, 0, 0, 0, 0); | |
thread->debugThread->scheduledOut = 0; | |
if ( this->eventsToFetch.count > 0x10 ) | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
KSynchronizationObject::NotifyWaiters(this, 0);// too many events in the queue already for these events | |
// | |
// Signal ourselves and try to schedule the debugger (the thread using ContinueDebugEvent) | |
userDebuggerCoreId = this->userDebuggerCoreId; | |
if ( g_coreLocalRegions[userDebuggerCoreId].clc.current.thread != this->userDebuggerThread ) | |
KDebug::RequestReschedulingForDebugger(this, userDebuggerCoreId); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
return v20; | |
} | |
else | |
{ | |
if ( type != DBGEVENT_SCHEDULE_OUT ) | |
kernelpanic(); | |
result = KDebug::EmplaceAysncEventInfo(this, DBGEVENT_SCHEDULE_OUT, 0, param1, 0, 0, 0, 0, 0); | |
thread->debugThread->scheduledOut = 1; | |
} | |
} | |
else | |
{ | |
LABEL_31: | |
switch ( type ) | |
{ | |
case DBGEVENT_EXIT_PROCESS: | |
case DBGEVENT_SCHEDULE_IN: | |
case DBGEVENT_SCHEDULE_OUT: | |
case DBGEVENT_SYSCALL_IN: | |
case DBGEVENT_SYSCALL_OUT: | |
case DBGEVENT_MAP: | |
return KDebug::ProcessAsyncEventAndEmplaceInfo(this, type, param1); | |
default: | |
KSchedulerLock::Lock(&this->lock); | |
while ( (current.clc.current.thread->schedulingMask & (unsigned __int8)KTHREADSCHEDSTAT_DEBUG_PAUSE_FLAG) != 0 ) | |
{ | |
KSchedulerLock::Unlock(&this->lock); | |
KSchedulerLock::Lock(&this->lock); | |
} | |
if ( this->signalingSyncEvent ) | |
kernelpanic(); | |
KDebug::BreakCurrentProcess(this, current.clc.current.thread); | |
v21 = current.clc.current.thread; | |
this->signalingSyncEventThread = current.clc.current.thread; | |
this->signalingSyncEvent = STOPPOINT_BREAKPOINT; | |
this->lastSyncDebugEventType = type; | |
if ( type == DBGEVENT_EXIT_THREAD ) | |
{ | |
v21->debugThread->exitReason = param1; | |
goto skip_exception; | |
} | |
if ( type < DBGEVENT_EXIT_THREAD ) // DBGEVENT_ATTACH_PROCESS = 0x0, | |
// DBGEVENT_ATTACH_THREAD = 0x1, | |
// DBGEVENT_EXIT_THREAD = 0x2, | |
{ | |
if ( type ) | |
{ | |
if ( type == DBGEVENT_ATTACH_THREAD ) | |
v21->debugThread->scheduledOut = STOPPOINT_BREAKPOINT; | |
} | |
else | |
{ | |
this->processAttached = STOPPOINT_BREAKPOINT; | |
v21->debugThread->scheduledOut = STOPPOINT_BREAKPOINT; | |
} | |
goto skip_exception; | |
} | |
if ( type != DBGEVENT_EXCEPTION ) | |
{ | |
if ( type == DBGEVENT_OUTPUT_STRING ) | |
{ | |
this->outputStringFlag = (param2 & 0x80000000) != 0; | |
this->outputStringSize = param2 & 0x7FFFFFFF; | |
this->outputStringAddr = param1; | |
} | |
goto skip_exception; | |
} | |
if ( (this->debugFlags & DBG_SIGNAL_FAULT_EXCEPTION_EVENTS) == 0 && param1 != EXCEVENT_STOP_POINT ) | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
this->signalingSyncEvent = 0; | |
KDebug::UnbreakCurrentProcess(this); | |
KSchedulerLock::Unlock(&this->lock); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
v21->debugThread->dfar = __mrc(15, 0, 6, 0, 0); | |
numExceptionEvents = this->numExceptionEvents; | |
if ( numExceptionEvents < 2 ) | |
this->numExceptionEvents = numExceptionEvents + 1; | |
switch ( param1 ) | |
{ | |
case EXCEVENT_PREFETCH_ABORT: | |
if ( (__mrc(15, 0, 5, 0, 1) & 0x40F) == 2 )// check ifsr | |
this->stopPointType = STOPPOINT_BREAKPOINT; | |
break; | |
case EXCEVENT_DATA_ABORT: | |
v23 = __mrc(15, 0, 5, 0, 0) & 0x40F;// check dfsr | |
if ( v23 == 1 ) | |
{ | |
param1 = EXCEVENT_UNALIGNED_DATA_ACCESS; | |
break; | |
} | |
if ( v23 == STOPPOINT_WATCHPOINT ) | |
goto LABEL_82; | |
break; | |
case EXCEVENT_STOP_POINT: | |
v23 = STOPPOINT_SVC_FF; | |
LABEL_82: | |
this->stopPointType = v23; | |
break; | |
case EXCEVENT_UNDEFINED_SYSCALL: | |
this->excCtx = 0; | |
this->svcId = param2; | |
goto LABEL_84; | |
} | |
this->excCtx = (ExceptionDispatchContext *)param2; | |
LABEL_84: | |
this->exceptionEventType = param1; | |
this->exceptionEventSignaled = STOPPOINT_BREAKPOINT; | |
v24 = (this->debugFlags & DBG_SIGNAL_FAULT_EXCEPTION_EVENTS) == 0; | |
if ( (this->debugFlags & 2) == 0 ) | |
v24 = param1 == EXCEVENT_STOP_POINT; | |
if ( v24 ) // stop point (svc 0xFF) bypasses this check | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
this->signalingSyncEvent = 0; | |
this->exceptionEventSignaled = 0; | |
this->excCtx = 0; | |
this->signalingSyncEventThread->debugThread->dfar = 0; | |
this->isFirstExceptionBreak = 0; | |
KDebug::UnbreakCurrentProcess(this); | |
KSchedulerLock::Unlock(&this->lock); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
if ( !this->excCtx ) | |
HIDWORD(ADJ(this->signalingSyncEventThread->kernelStackTop)[-1].ctx.d[12]) = STOPPOINT_BREAKPOINT;// set lr & ask to reload user regs | |
skip_exception: | |
KDebug::EmplaceSyncEventInfo(this); | |
result = KDebug::PauseSignalingThread(this, this->signalingSyncEventThread); | |
v25 = result; | |
if ( result >= 0 ) | |
{ | |
switch ( type ) | |
{ | |
case DBGEVENT_ATTACH_THREAD: | |
current.clc.current.thread->debugThread->attached = STOPPOINT_BREAKPOINT; | |
break; | |
case DBGEVENT_EXIT_THREAD: | |
KDebug::DetachThread(this, current.clc.current.thread); | |
break; | |
case DBGEVENT_EXCEPTION: | |
v26 = this->debugFlags; | |
this->isFirstExceptionBreak = 0; | |
if ( (v26 & 1) != 0 ) | |
v25 = 0x96007F9; | |
break; | |
} | |
result = v25; | |
} | |
break; | |
} | |
} | |
return result; | |
} | |
} | |
// FFF1825C: control flows out of bounds to FFF18260 | |
// FFF182B8: control flows out of bounds to FFF182BC | |
// FFF18400: control flows out of bounds to FFF18404 | |
//----- (FFF18834) -------------------------------------------------------- | |
void __fastcall KScheduler::TrySwitchingThread(KScheduler *this) | |
{ | |
this->reschedule = 1; | |
if ( !this->disableCount ) | |
KScheduler::SwitchThread(this, 0); | |
} | |
//----- (FFF18854) -------------------------------------------------------- | |
Result __fastcall KDebug::BuildOrderedListOfThreads(KDebug *this) | |
{ | |
int i; // r5 | |
KThread *volatile thread; // r4 | |
KLinkedListNode *v4; // r0 | |
int v5; // r0 | |
int j; // r9 | |
KThread *k; // r4 | |
KLinkedListNode *v8; // r0 | |
char cfgr; // r0 | |
for ( i = 0; ; ++i ) | |
{ | |
v5 = (MPCORE.scu.cfgr & 3) + 1; | |
if ( v5 <= i ) | |
break; | |
thread = g_coreLocalRegions[i].clc.current.thread; | |
if ( thread->owner == this->process ) // if the owner is the attached process & the thread is in the KCurrentContext, then we can safely report it's the current thread | |
// | |
// Put them first in the list | |
{ | |
v4 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v4 ) | |
{ | |
v4->link.next = 0; | |
v4->link.prev = 0; | |
v4->data = 0; | |
} | |
v4->data = thread; | |
KLinkedList::InsertAfter( | |
(KLinkedList *)&this->orderedThreadListForBreak, | |
(KLinkedListLink *)&this->orderedThreadListForBreak.link, | |
v4); | |
} | |
} | |
for ( j = 0; ; ++j ) | |
{ | |
cfgr = MPCORE.scu.cfgr; // then all the other threads, per core then per dynamic priority | |
if ( (cfgr & 3) + 1 <= j ) | |
break; | |
for ( k = KScheduler::GetNextQueuedThread(&g_coreLocalRegions[j].clc.schedulerInstance, 0); | |
k; | |
k = KScheduler::GetNextQueuedThread(&g_coreLocalRegions[j].clc.schedulerInstance, k) ) | |
{ | |
if ( k->owner == this->process ) | |
{ | |
v8 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v8 ) | |
{ | |
v8->link.next = 0; | |
v8->link.prev = 0; | |
v8->data = 0; | |
} | |
v8->data = k; | |
KLinkedList::InsertAfter( | |
(KLinkedList *)&this->orderedThreadListForBreak, | |
(KLinkedListLink *)&this->orderedThreadListForBreak.link, | |
v8); | |
} | |
} | |
} | |
return 0; | |
} | |
// FFF188B4: conditional instruction was optimized away because r0.4!=0 | |
// FFF18968: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF189D4) -------------------------------------------------------- | |
Result __fastcall KDebug::RequestPause(KDebug *this, KThread *thread) | |
{ | |
KThread *v3; // r1 | |
KThreadStackParameters *v4; // r0 | |
unsigned __int8 *p_dpcFlags; // r0 | |
unsigned __int8 v6; // r2 | |
v3 = (KThread *)__ldrex((unsigned int *)&g_eventSignalMutex); | |
if ( v3 && v3 == thread ) // if we hold the mutex, don't pause here | |
{ | |
thread->debugThread->debugPauseRequested = 1; | |
v4 = ADJ(thread->kernelStackTop) + 1; | |
if ( v4[-1].svcId ) | |
{ | |
p_dpcFlags = &v4[-1].dpcFlags; | |
do | |
v6 = __ldrex(p_dpcFlags); | |
while ( __strex(v6 | KDPCFLAG_DEBUG_PAUSE, p_dpcFlags) );// the check in post-svc is broken, in reality | |
} | |
return 0; | |
} | |
else | |
{ | |
KThread::SetDebugPauseState(thread, 1); | |
return 0; | |
} | |
} | |
//----- (FFF18A54) -------------------------------------------------------- | |
Result __fastcall KDebug::GetThreadVfpContext( | |
KDebug *this, | |
ThreadContext *outThreadContext, | |
KThread *thread, | |
ThreadContextControlFlags flags) | |
{ | |
unsigned int CPSR; // r4 | |
__int32 v6; // r5 | |
KThreadContext *context; // r7 | |
s32 v8; // r0 | |
char cfgr; // r1 | |
Result result; // r0 | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
v6 = flags & THREADCONTEXT_CONTROL_MAX; | |
if ( (flags & THREADCONTEXT_CONTROL_FPU_REGS) != 0 ) | |
{ | |
context = thread->context; | |
v8 = 0; | |
cfgr = MPCORE.scu.cfgr; | |
while ( (cfgr & 3) + 1 > v8 ) | |
{ | |
if ( thread == *(KThread **)(0x9000 * v8 + 0xFFFD1010) )// current thread with vfp enabled? | |
{ | |
KVfpRegisterDumpHelper::DumpAndDisableVfpRegsForCore(v8); | |
break; | |
} | |
++v8; | |
} | |
if ( (v6 & 0x100008) != 0 ) | |
{ | |
outThreadContext->fpuRegisters.fpexc = context->fpexc | 0x40000000;// set "vfp initialized" flag | |
outThreadContext->fpuRegisters.fpscr = context->fpscr; | |
} | |
if ( (v6 & THREADCONTEXT_CONTROL_FPU_GPRS_ALLFLAGS) != 0 ) | |
qmemcpy(&outThreadContext->fpuRegisters, context->d, 0x80u); | |
} | |
result = 0; | |
__set_CPSR(CPSR); | |
return result; | |
} | |
//----- (FFF18B20) -------------------------------------------------------- | |
Result __fastcall KAutoObject::Initialize(KAutoObject *this) | |
{ | |
unsigned int *p_refcount; // r2 | |
unsigned int v3; // r0 | |
p_refcount = (unsigned int *)&this->refcount; | |
do | |
v3 = __ldrex(p_refcount); | |
while ( __strex(v3 + 1, p_refcount) ); | |
if ( !this->refcount ) | |
kernelpanic(); | |
return (Result)this; | |
} | |
//----- (FFF18B58) -------------------------------------------------------- | |
KMemoryBlock *__fastcall KMemoryBlockManager::GetMemoryBlockContainingAddr(KMemoryBlockManager *this, u32 addr) | |
{ | |
KMemoryBlockLinkedListNode *i; // r4 | |
for ( i = this->blocks.link.next; i != (KMemoryBlockLinkedListNode *)&this->blocks.link; i = i->link.next ) | |
{ | |
if ( KMemoryBlock::Contains(i->block, addr) ) | |
return i->block; | |
} | |
return 0; | |
} | |
//----- (FFF18B9C) -------------------------------------------------------- | |
void __fastcall KMemoryBlockManager::DumpInfoMaybe_stubbed(KMemoryBlockManager *this) | |
{ | |
KMemoryBlockLinkedListNode *it; // r4 | |
KMemoryInfo v3; // [sp+0h] [bp-20h] BYREF | |
for ( it = this->blocks.link.next; it != (KMemoryBlockLinkedListNode *)&this->blocks.link; it = it->link.next ) | |
KMemoryBlock::GetInfo(&v3, it->block); | |
} | |
//----- (FFF18BD4) -------------------------------------------------------- | |
void __fastcall KScheduler::RemoveThread(KScheduler *this, KThread *thread, s32 prio) | |
{ | |
KScheduler *p_schedulerInstance; // r3 | |
KThreadIntrusiveLink *p_link; // r12 | |
KThread *next; // r4 | |
KThread *prev; // r2 | |
KThread *v7; // r4 | |
KThreadIntrusiveLink *v8; // r6 | |
p_schedulerInstance = &g_coreLocalRegions[thread->coreId].clc.schedulerInstance; | |
p_link = &p_schedulerInstance->threadsByPrio[prio].link; | |
next = p_schedulerInstance->threadsByPrio[prio].link.next; | |
if ( next && next == p_link->prev ) // v4->next = first thread, ie no more threads in the list | |
g_coreLocalRegions[thread->coreId].clc.schedulerInstance.prioBitfield[(unsigned int)prio >> 5] &= ~(0x80000000 >> (prio & 0x1F)); | |
__mcr(15, 0, 0, 7, 10, 5); | |
prev = thread->link.prev; | |
v7 = thread->link.next; | |
if ( prev ) | |
v8 = &prev->link; | |
else | |
v8 = p_link; | |
if ( v7 ) | |
p_link = &v7->link; | |
v8->next = v7; | |
p_link->prev = prev; | |
--p_schedulerInstance->numThreads; | |
if ( g_coreLocalRegions[p_schedulerInstance->coreId].clc.current.thread == thread ) | |
{ | |
p_schedulerInstance->reschedule = 1; | |
this->triggerSgi = 1; | |
} | |
} | |
//----- (FFF18C8C) -------------------------------------------------------- | |
void __fastcall KScheduler::TriggerSgi(KScheduler *this) | |
{ | |
int v1; // r1 | |
char cfgr; // r2 | |
v1 = 0; | |
this->triggerSgi = 0; | |
cfgr = MPCORE.scu.cfgr; | |
while ( (cfgr & 3) + 1 > v1 ) | |
{ | |
if ( this->coreId != v1 ) | |
{ | |
if ( *(_BYTE *)(0x9000 * v1 + 0xFFFD10D4) )// KCoreLocalContext.schedulerInstance.reschedule | |
MPCORE.gicd.sgir = (1 << v1 << 16) & 0xFF0000 | KINTNAME_SGI_SCHEDULER; | |
} | |
++v1; | |
} | |
} | |
//----- (FFF18D08) -------------------------------------------------------- | |
KDmaBlockBase *__fastcall KDmaBlockBase::KDmaBlockBase(KDmaBlockBase *this) | |
{ | |
this->prologueChild = 0; | |
this->__vftable = &KDmaBlockBase::vt; | |
this->bodyChild = 0; | |
this->epilogueChild = 0; | |
this->mainSize = 0; | |
this->dstInterval = 0; | |
this->srcInterval = 0; | |
this->blockType = KDMABLOCKTYPE_BODY; | |
this->direction = KDMADIRECTION_NONE; | |
this->wfpDirection = KDMADIRECTION_NONE; | |
this->notificationDirection = 0; | |
this->strideDirection = 0; | |
this->channelId = -1; | |
this->loopDepth = 0; | |
this->dmaSize.size = 0; | |
this->dmaSize.dstBufferSize.pos = 0; | |
this->dmaSize.dstBufferSize.minOffset = 0; | |
this->dmaSize.dstBufferSize.maxOffset = 0; | |
this->dmaSize.srcBufferSize.pos = 0; | |
this->dmaSize.srcBufferSize.minOffset = 0; | |
this->dmaSize.srcBufferSize.maxOffset = 0; | |
this->numBlocks = 0; | |
return this; | |
} | |
//----- (FFF18D78) -------------------------------------------------------- | |
void SignalNewThreadEntry(void) | |
{ | |
DispatchDebugEvent(DBGEVENT_ATTACH_PROCESS, 0, 0); | |
} | |
//----- (FFF18DB0) -------------------------------------------------------- | |
Result __fastcall DispatchDebugEvent(DebugEventType type, u32 param1, u32 param2) | |
{ | |
int debug; // r12 | |
KProcess *volatile process; // r2 | |
bool v6; // r5 | |
bool v7; // zf | |
process = current.clc.current.process; | |
if ( type == DBGEVENT_SCHEDULE_IN ) | |
{ | |
if ( !g_scheduledOut[__mrc(15, 0, 0, 0, 5) & 3] ) | |
return 0; | |
debug = __mrc(15, 0, 0, 0, 5) & 3; | |
v6 = 0; | |
} | |
else | |
{ | |
if ( type != DBGEVENT_SCHEDULE_OUT ) | |
goto LABEL_7; | |
debug = __mrc(15, 0, 0, 0, 5) & 3; | |
v6 = 1; | |
} | |
g_scheduledOut[debug] = v6; | |
LABEL_7: | |
v7 = process == 0; | |
if ( process ) | |
{ | |
debug = (int)process->debug; | |
v7 = debug == 0; | |
} | |
if ( !v7 ) | |
return KDebug::DispatchEvent((KDebug *)debug, type, param1, param2); | |
return 0; | |
} | |
// FFF18E2C: variable 'debug' is possibly undefined | |
// FFF2F058: using guessed type bool g_scheduledOut[8]; | |
//----- (FFF18E44) -------------------------------------------------------- | |
void __fastcall KAutoObject::IncrementRefcount(KAutoObject *this) | |
{ | |
unsigned int *p_refcount; // r2 | |
unsigned int v2; // r1 | |
p_refcount = (unsigned int *)&this->refcount; | |
do | |
v2 = __ldrex(p_refcount); | |
while ( __strex(v2 + 1, p_refcount) ); | |
if ( !this->refcount ) | |
kernelpanic(); | |
} | |
//----- (FFF18E80) -------------------------------------------------------- | |
KAutoObject *__fastcall KHandleTable::ConvertToAutoObject(KHandleTable *this, Handle handle) | |
{ | |
unsigned int *p_mutex; // r0 | |
KLightMutex *v5; // r4 | |
unsigned int v6; // r2 | |
bool v7; // zf | |
KLightMutex *v8; // r0 | |
signed __int32 v9; // r0 | |
Handle v10; // r1 | |
bool v11; // cc | |
KHandleTableEntry *v12; // r5 | |
KAutoObject *object; // r0 | |
KAutoObject *v14; // r5 | |
p_mutex = (unsigned int *)&this->mutex; | |
v5 = (KLightMutex *)p_mutex; | |
v6 = __ldrex(p_mutex); | |
v7 = v6 == 0; | |
if ( v6 ) | |
__strex(v6, p_mutex); | |
else | |
v6 = __strex((unsigned int)current.clc.current.thread, p_mutex); | |
if ( v7 ) | |
v7 = v6 == 0; | |
if ( !v7 ) | |
KLightMutex::LockImpl((KLightMutex *)p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( (handle & 0xC0000000) != 0 ) | |
{ | |
v8 = v5; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v5->lockingThread = 0; | |
if ( v5->numWaiters <= 0 ) | |
return 0; | |
LABEL_10: | |
KLightMutex::UnlockImpl(v8); | |
return 0; | |
} | |
v9 = handle & 0x7FFF; | |
v10 = handle >> 15; | |
if ( !handle ) | |
goto LABEL_20; | |
v11 = v10 == 0; | |
if ( v10 ) | |
v11 = this->handleTableSize <= v9; | |
if ( v11 || (v12 = &this->entries[v9], (object = v12->used.object) == 0) || LOWORD(v12->free.next) != v10 ) | |
{ | |
LABEL_20: | |
v8 = v5; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v5->lockingThread = 0; | |
if ( v5->numWaiters <= 0 ) | |
return 0; | |
goto LABEL_10; | |
} | |
KAutoObject::IncrementRefcount(object); | |
v14 = v12->used.object; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v5->lockingThread = 0; | |
if ( v5->numWaiters > 0 ) | |
KLightMutex::UnlockImpl(v5); | |
return v14; | |
} | |
//----- (FFF18F80) -------------------------------------------------------- | |
Result __fastcall KHandleTable::Add(KHandleTable *this, Handle *outHandle, KAutoObject *obj, u8 typeId) | |
{ | |
unsigned int *p_mutex; // r0 | |
KLightMutex *v9; // r5 | |
unsigned int v10; // r2 | |
bool v11; // zf | |
unsigned int v12; // r3 | |
Result v13; // r4 | |
KLightMutex *v14; // r0 | |
KHandleTableEntry *firstFreeEntry; // r0 | |
unsigned int v16; // r2 | |
int nextId; // r1 | |
int v18; // r9 | |
int v19; // r0 | |
unsigned int v20; // r0 | |
p_mutex = (unsigned int *)&this->mutex; | |
v9 = (KLightMutex *)p_mutex; | |
v10 = __ldrex(p_mutex); | |
v11 = v10 == 0; | |
if ( v10 ) | |
v12 = __strex(v10, p_mutex); | |
else | |
v12 = __strex((unsigned int)current.clc.current.thread, p_mutex); | |
if ( !v10 ) | |
v11 = v12 == 0; | |
if ( !v11 ) | |
KLightMutex::LockImpl((KLightMutex *)p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( this->count < this->handleTableSize ) | |
{ | |
firstFreeEntry = this->firstFreeEntry; | |
this->firstFreeEntry = (KHandleTableEntry *)firstFreeEntry->used.info; | |
v16 = ((char *)firstFreeEntry - (char *)this->entries) << 14; | |
nextId = this->nextId; | |
firstFreeEntry->used.object = obj; | |
LOWORD(firstFreeEntry->free.next) = nextId; | |
BYTE2(firstFreeEntry->used.info) = typeId; | |
v18 = (v16 >> 17) | (nextId << 15); | |
v19 = (__int16)(this->count + 1); | |
this->count = v19; | |
if ( this->maxCount >= v19 ) | |
LOWORD(v19) = this->maxCount; | |
this->maxCount = v19; | |
KAutoObject::IncrementRefcount(obj); | |
v20 = (unsigned __int16)(this->nextId + 1); | |
this->nextId = v20; | |
if ( v20 >= 0x8000 ) | |
this->nextId = 1; | |
v13 = 0; | |
v14 = v9; | |
*outHandle = v18; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v9->lockingThread = 0; | |
if ( v9->numWaiters > 0 ) | |
goto LABEL_10; | |
} | |
else | |
{ | |
v13 = -664796141; | |
v14 = v9; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v9->lockingThread = 0; | |
if ( v9->numWaiters > 0 ) | |
LABEL_10: | |
KLightMutex::UnlockImpl(v14); | |
} | |
return v13; | |
} | |
//----- (FFF190A8) -------------------------------------------------------- | |
Result __fastcall KPageTable::CheckAddrRangeMaskedStateAndPerms( | |
KPageTable *this, | |
u32 addr, | |
u32 size, | |
KMemoryState stateMask, | |
KMemoryState expectedState, | |
KMemoryPermission minPerms) | |
{ | |
Result result; // r0 | |
u32 v11; // r1 | |
u32 v12[4]; // [sp+0h] [bp-40h] BYREF | |
KMemoryInfo outMemoryInfo; // [sp+10h] [bp-30h] BYREF | |
if ( size && addr > addr + size - 1 ) | |
return 0xE0A01BF5; | |
while ( 1 ) | |
{ | |
result = KPageTable::QueryInfo(this, &outMemoryInfo, v12, addr); | |
if ( result < 0 ) | |
break; | |
if ( (outMemoryInfo.state & stateMask) != expectedState || (minPerms & ~outMemoryInfo.perms) != 0 ) | |
return 0xE0A01BF5; | |
if ( outMemoryInfo.baseAddress + outMemoryInfo.size >= addr + size ) | |
return 0; | |
v11 = outMemoryInfo.baseAddress + outMemoryInfo.size - addr; | |
addr = outMemoryInfo.baseAddress + outMemoryInfo.size; | |
size -= v11; | |
} | |
return result; | |
} | |
//----- (FFF1915C) -------------------------------------------------------- | |
bool KDmaController::IsManagerFaulting(void) | |
{ | |
char fsrd; // r0 | |
fsrd = CDMA.fsrd; | |
return (fsrd & 1) != 0; | |
} | |
//----- (FFF19174) -------------------------------------------------------- | |
bool __fastcall KDmaController::IsChannelFaulting(s8 channelId) | |
{ | |
u32 fsrc; // r2 | |
fsrc = CDMA.fsrc; | |
return (fsrc & (1 << channelId)) != 0; | |
} | |
//----- (FFF19190) -------------------------------------------------------- | |
u32 __fastcall KDmaController::GetChannelStatus(s8 channelId) | |
{ | |
return CDMA.chan_stat[channelId].csr & 0xF; | |
} | |
//----- (FFF191A8) -------------------------------------------------------- | |
Result __fastcall KPageTable::OperateOnGroup( | |
KPageTable *this, | |
u32 addr, | |
KPageGroup *pgGroup, | |
KMemoryState state, | |
KMemoryPermission perms, | |
KMemoryUpdateFlags updateFlags) | |
{ | |
int v9; // r1 | |
KBlockInfoLinkedListNode *next; // r4 | |
KBlockInfo *blockInfo; // r0 | |
v9 = 0x82007FF; | |
next = pgGroup->list.link.next; | |
while ( next != (KBlockInfoLinkedListNode *)&pgGroup->list.link ) | |
{ | |
v9 = KPageTable::Operate( | |
this, | |
addr, | |
next->blockInfo->numPages, | |
next->blockInfo->baseAddress - 0xC0000000, | |
state, | |
perms, | |
updateFlags, | |
MEMOP_REGION_BASE); | |
if ( v9 < 0 ) | |
break; | |
blockInfo = next->blockInfo; | |
next = next->link.next; | |
addr += blockInfo->numPages << 12; | |
} | |
return v9; | |
} | |
//----- (FFF1922C) -------------------------------------------------------- | |
u32 __fastcall KMemoryManager::AllocateContiguous( | |
KMemoryManager *this, | |
u32 numPages, | |
u32 pageAlignment, | |
MemoryOperation op) | |
{ | |
unsigned int *p_mutex; // r0 | |
KLightMutex *v9; // r4 | |
unsigned int v10; // r2 | |
bool v11; // zf | |
unsigned int v12; // r3 | |
unsigned int *p_kernelMemoryUsage; // r0 | |
unsigned int v14; // r1 | |
__int32 v15; // r0 | |
void *addr; // r6 | |
KLightMutex *v17; // r0 | |
p_mutex = (unsigned int *)&this->pgMgr.mutex; | |
v9 = (KLightMutex *)p_mutex; | |
v10 = __ldrex(p_mutex); | |
v11 = v10 == 0; | |
if ( v10 ) | |
v12 = __strex(v10, p_mutex); | |
else | |
v12 = __strex((unsigned int)current.clc.current.thread, p_mutex); | |
if ( !v10 ) | |
v11 = v12 == 0; | |
if ( !v11 ) | |
KLightMutex::LockImpl((KLightMutex *)p_mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( op < MEMOP_NONE ) | |
{ | |
p_kernelMemoryUsage = &this->pgMgr.kernelMemoryUsage; | |
do | |
v14 = __ldrex(p_kernelMemoryUsage); | |
while ( __strex(v14 + (numPages << 12), p_kernelMemoryUsage) ); | |
} | |
v15 = op & 0xF00; | |
if ( v15 == 256 ) | |
{ | |
addr = KPageHeap::AllocateContiguous(&this->applicationHeap, numPages, pageAlignment); | |
v17 = v9; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v9->lockingThread = 0; | |
if ( v9->numWaiters <= 0 ) | |
return (u32)addr; | |
goto LABEL_17; | |
} | |
if ( v15 == 512 ) | |
{ | |
addr = KPageHeap::AllocateContiguous(&this->systemHeap, numPages, pageAlignment); | |
v17 = v9; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v9->lockingThread = 0; | |
if ( v9->numWaiters <= 0 ) | |
return (u32)addr; | |
goto LABEL_17; | |
} | |
if ( v15 != 768 ) | |
kernelpanic(); | |
addr = KPageHeap::AllocateContiguous(&this->baseHeap, numPages, pageAlignment); | |
v17 = v9; | |
__mcr(15, 0, 0, 7, 10, 5); | |
v9->lockingThread = 0; | |
if ( v9->numWaiters > 0 ) | |
LABEL_17: | |
KLightMutex::UnlockImpl(v17); | |
return (u32)addr; | |
} | |
//----- (FFF1937C) -------------------------------------------------------- | |
void *__fastcall KPageHeap::AllocateContiguous(KPageHeap *this, u32 size, u32 pageAlignment) | |
{ | |
KPageHeapBlock *currentNode; // r4 | |
bool v7; // zf | |
u32 misalignment; // r6 | |
u32 regionSize; // r0 | |
u32 numPages; // r8 | |
u32 v11; // r1 | |
KPageHeapBlock *next; // r6 | |
KPageHeapBlock *v13; // r1 | |
KPageHeap *v14; // r0 | |
u32 v15; // r1 | |
u32 v16; // r2 | |
u32 v17; // r8 | |
u32 v18; // r3 | |
int i; // lr | |
int v20; // r12 | |
int v21; // r0 | |
KPageHeapBlock *j; // r4 | |
KPageHeapBlock *prev; // [sp+0h] [bp-30h] | |
KPageHeapBlock *block; // [sp+4h] [bp-2Ch] | |
currentNode = this->link.next; | |
v7 = this->link.next == 0; | |
if ( this->link.next ) | |
v7 = this->link.prev == 0; | |
if ( !v7 ) | |
v7 = size == 0; | |
if ( v7 ) | |
return 0; | |
do | |
{ | |
misalignment = 0; | |
KPageHeap::ValidateBlock(this, currentNode); | |
regionSize = this->regionSize; | |
numPages = currentNode->numPages; | |
if ( currentNode->numPages > regionSize >> 12 | |
|| regionSize + this->regionStart < (unsigned int)currentNode + 4096 * numPages ) | |
{ | |
kernelpanic(); | |
} | |
if ( pageAlignment > 1 ) | |
{ | |
v11 = ((unsigned int)currentNode >> 12) % pageAlignment; | |
if ( v11 ) | |
misalignment = pageAlignment - v11; | |
} | |
if ( size + misalignment <= numPages ) | |
{ | |
block = currentNode; | |
if ( misalignment ) | |
block = KPageHeap::SplitBlock(this, currentNode, misalignment); | |
KPageHeap::SplitBlock(this, block, size); | |
KPageHeap::ValidateBlock(this, block); | |
prev = block->link.prev; | |
next = block->link.next; | |
KPageHeap::ValidateBlock(this, prev); | |
KPageHeap::ValidateBlock(this, next); | |
if ( prev ) | |
{ | |
prev->link.next = next; | |
v13 = prev; | |
v14 = this; | |
} | |
else | |
{ | |
this->link.next = next; | |
if ( !next ) | |
{ | |
this->link.prev = 0; | |
goto LABEL_28; | |
} | |
v15 = this->key[0]; | |
v16 = this->key[1]; | |
v17 = this->key[2]; | |
v18 = this->key[3]; | |
for ( i = 0; i < 2; ++i ) | |
{ | |
v20 = 0; | |
do | |
{ | |
v21 = *(u32 *)((char *)&next->numPages + v20); | |
v20 += 4; | |
v15 -= v21 - __ROR4__(v16, 3); | |
v16 -= __ROR4__(v17, (v18 & 0xF) + 3) ^ __ROR4__(v18, (v15 & 0xF) + 13); | |
v17 -= __ROR4__(v18, v15) * v16; | |
v18 -= __ROR4__(v15, v16) * v17; | |
} | |
while ( v20 < 20 ); | |
} | |
if ( (v15 ^ v16) != next->mac ) | |
kernelpanic(); | |
this->link.next->link.prev = 0; | |
v13 = this->link.next; | |
v14 = this; | |
} | |
KPageHeap::UpdateBlockMac(v14, v13); | |
if ( next ) | |
{ | |
next->link.prev = prev; | |
KPageHeap::UpdateBlockMac(this, next); | |
LABEL_29: | |
if ( block->numPages != size ) | |
kernelpanic(); | |
return block; | |
} | |
LABEL_28: | |
KPageHeap::SetLastBlock(this, prev); | |
goto LABEL_29; | |
} | |
currentNode = currentNode->link.next; | |
} | |
while ( currentNode ); | |
for ( j = this->link.next; j; j = j->link.next ) | |
KPageHeap::ValidateBlock(this, j); | |
return 0; | |
} | |
//----- (FFF195C0) -------------------------------------------------------- | |
void __fastcall KPageManager::IncrefPages(KPageManager *this, u32 addr, u32 numPages) | |
{ | |
u32 v3; // r1 | |
unsigned int endOff; // r2 | |
char v5; // cc | |
int v6; // r12 | |
int v7; // r2 | |
int v8; // r3 | |
u32 v9; // r5 | |
int v10; // r3 | |
u32 v11; // r6 | |
v3 = (addr - this->memoryStartAddr) >> 12; | |
endOff = numPages + v3; | |
v5 = (endOff != 0x7FFFFFFF) & __CFADD__(endOff, 0x80000001);// if (endOff < 0 || startOff < 0) | |
// | |
// ... what? | |
if ( endOff <= 0x7FFFFFFF ) | |
v5 = (v3 != 0x7FFFFFFF) & __CFADD__(v3, 0x80000001); | |
if ( v5 ) | |
{ | |
for ( ; v3 < endOff; ++v3 ) | |
++this->pageRefcounts[v3]; | |
} | |
else | |
{ | |
v6 = endOff - v3; | |
if ( (int)(endOff - v3) > 0 ) | |
{ | |
v7 = v6 & 1; | |
v8 = 0; | |
if ( v7 == 1 ) | |
{ | |
v8 = 1; | |
++this->pageRefcounts[v3]; | |
} | |
for ( ; v6 > v7; ++this->pageRefcounts[v11] ) | |
{ | |
v9 = v3 + v8; | |
v10 = v8 + 1; | |
v11 = v3 + v10; | |
v7 += 2; | |
++this->pageRefcounts[v9]; | |
v8 = v10 + 1; | |
} | |
} | |
} | |
} | |
//----- (FFF19688) -------------------------------------------------------- | |
Result __fastcall KPageTable::SplitContiguousEntries(KPageTable *this, u32 va, u32 size) | |
{ | |
unsigned int L1Entry; // r7 | |
int L1EntryType; // r0 | |
int v7; // r0 | |
unsigned int v8; // r4 | |
u32 v9; // r1 | |
__int16 v10; // r0 | |
unsigned int v11; // r7 | |
unsigned int m; // r0 | |
int v13; // r3 | |
unsigned int v14; // r2 | |
unsigned int v15; // r2 | |
bool v16; // zf | |
unsigned int v17; // r3 | |
KLevel2TranslationTable *rootNode; // r4 | |
unsigned int v19; // r1 | |
bool v20; // zf | |
unsigned int v21; // r2 | |
unsigned int i; // r11 | |
KLevel2TranslationTable *v23; // r0 | |
KLevel2TranslationTable *v24; // r1 | |
__int16 v25; // r0 | |
unsigned int v26; // r12 | |
unsigned int j; // r3 | |
int v28; // r2 | |
char *v29; // r0 | |
int v30; // r1 | |
unsigned int k; // r11 | |
unsigned int v32; // r1 | |
bool v33; // zf | |
int v34; // r3 | |
unsigned int v35; // r2 | |
u32 v36; // r1 | |
int v37; // r4 | |
int v38; // r0 | |
int v39; // r12 | |
L1Entry = this->L1Table[va >> 20]; | |
L1EntryType = L1Entry & 0x40003; | |
if ( (L1Entry & 0x40003) != 1 ) | |
{ | |
if ( L1EntryType == 2 ) | |
{ | |
sectionOnly: | |
if ( size >= 0x100000 ) | |
return 0; | |
v15 = __ldrex((unsigned int *)&g_level2TtblAllocator.mutex); | |
v16 = v15 == 0; | |
if ( v15 ) | |
v17 = __strex(v15, (unsigned int *)&g_level2TtblAllocator.mutex); | |
else | |
v17 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_level2TtblAllocator.mutex); | |
if ( !v15 ) | |
v16 = v17 == 0; | |
if ( !v16 ) | |
KLightMutex::LockImpl(&g_level2TtblAllocator.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
rootNode = g_level2TtblAllocator.rootNode; | |
if ( g_level2TtblAllocator.rootNode ) | |
{ | |
if ( g_level2TtblAllocator.rootNode->next == g_level2TtblAllocator.rootNode ) | |
{ | |
g_level2TtblAllocator.rootNode = 0; | |
} | |
else | |
{ | |
g_level2TtblAllocator.rootNode = g_level2TtblAllocator.rootNode->prev; | |
rootNode->prev->next = rootNode->next; | |
rootNode->next->prev = rootNode->prev; | |
} | |
rootNode->prev = 0; | |
rootNode->next = 0; | |
--g_level2TtblAllocator.numAvailable; | |
} | |
else | |
{ | |
rootNode = (KLevel2TranslationTable *)KMemoryManager::AllocateContiguous( | |
&g_memoryManager, | |
1u, | |
0, | |
MEMOP_REGION_BASE_KERNEL); | |
if ( !rootNode ) | |
{ | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_level2TtblAllocator.mutex.lockingThread = 0; | |
if ( g_level2TtblAllocator.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_level2TtblAllocator.mutex); | |
LABEL_46: | |
kernelpanic(); | |
} | |
v19 = __ldrex((unsigned int *)&g_memoryManager.pgMgr.mutex); | |
v20 = v19 == 0; | |
if ( v19 ) | |
v21 = __strex(v19, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
else | |
v21 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_memoryManager.pgMgr.mutex); | |
if ( !v19 ) | |
v20 = v21 == 0; | |
if ( !v20 ) | |
KLightMutex::LockImpl(&g_memoryManager.pgMgr.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KPageManager::IncrefPages(&g_memoryManager.pgMgr, (u32)rootNode, 1u); | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_memoryManager.pgMgr.mutex.lockingThread = 0; | |
if ( g_memoryManager.pgMgr.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_memoryManager.pgMgr.mutex); | |
for ( i = 1; i < 4; ++i ) | |
{ | |
v23 = &rootNode[128 * i]; | |
if ( v23 ) | |
{ | |
v23->next = 0; | |
v23->prev = 0; | |
} | |
v24 = g_level2TtblAllocator.rootNode; | |
if ( g_level2TtblAllocator.rootNode ) | |
{ | |
v23->prev = g_level2TtblAllocator.rootNode; | |
v24->next->prev = v23; | |
v23->next = v24->next; | |
v24->next = v23; | |
} | |
else | |
{ | |
v23->prev = v23; | |
v23->next = v23; | |
} | |
g_level2TtblAllocator.rootNode = v23; | |
} | |
g_level2TtblAllocator.numAvailable += 3; | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_level2TtblAllocator.mutex.lockingThread = 0; | |
if ( g_level2TtblAllocator.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_level2TtblAllocator.mutex); | |
if ( !rootNode ) | |
goto LABEL_46; | |
v25 = L1Entry & 0xC | ((unsigned __int16)(L1Entry & 0x7000) >> 6) | ((L1Entry & 0x38C00) >> 6) | ((unsigned __int8)(L1Entry & 0x10) >> 4); | |
v26 = ((unsigned __int16)(L1Entry & 0x7000) >> 6) & 0x30 | ((L1Entry & 0x38C00) >> 6) & 0xE30 | ((unsigned __int8)(L1Entry & 0x10) >> 4) & 0x30 | 1 | v25 & 0xC | ((v25 & 1) << 15) | ((((unsigned __int16)(L1Entry & 0x7000) >> 6) & 0x1C0 | ((L1Entry & 0x38C00) >> 6) & 0xC0 | ((unsigned __int8)(L1Entry & 0x10) >> 4) & 0xC0) << 6); | |
for ( j = 0; j < 0x10; ++j ) | |
{ | |
v28 = ((L1Entry >> 20 << 20) + (j << 16)) | v26; | |
v29 = (char *)rootNode + ((((va >> 20 << 20) + (j << 16)) & 0xFF000) >> 10) - 4; | |
v30 = 8; | |
do | |
{ | |
*((_DWORD *)v29 + 1) = v28; | |
--v30; | |
*((_DWORD *)v29 + 2) = v28; | |
v29 += 8; | |
} | |
while ( v30 ); | |
} | |
for ( k = 0; k < 0x100; ++k ) | |
{ | |
v32 = __ldrex((unsigned int *)&g_level2TtblAllocator.mutex); | |
v33 = v32 == 0; | |
if ( v32 ) | |
__strex(v32, (unsigned int *)&g_level2TtblAllocator.mutex); | |
else | |
v32 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)&g_level2TtblAllocator.mutex); | |
if ( v33 ) | |
v33 = v32 == 0; | |
if ( !v33 ) | |
KLightMutex::LockImpl(&g_level2TtblAllocator.mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
++g_level2TtblAllocator.refcounts[((unsigned int)rootNode - g_level2TtblAllocator.baseRegionStart) >> 10]; | |
__mcr(15, 0, 0, 7, 10, 5); | |
g_level2TtblAllocator.mutex.lockingThread = 0; | |
if ( g_level2TtblAllocator.mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&g_level2TtblAllocator.mutex); | |
} | |
KPageTable::CleanDataCacheRange((u32)rootNode, 0x400u); | |
L1Entry = ((unsigned int)&rootNode[0x8000000] >> 10 << 10) | 1; | |
this->L1Table[va >> 20] = L1Entry; | |
KPageTable::CleanDataCacheRange((u32)&this->L1Table[va >> 20], 4u); | |
goto LABEL_63; | |
} | |
v7 = L1EntryType - 262145; | |
if ( v7 ) | |
{ | |
if ( v7 != 1 || size >= 0x1000000 ) | |
return 0; | |
v8 = L1Entry & 0xFF000000; | |
v9 = va & 0xFF000000; | |
v10 = L1Entry & 0xC | ((unsigned __int16)(L1Entry & 0x7000) >> 6) | ((L1Entry & 0x38C00) >> 6) | ((unsigned __int8)(L1Entry & 0x10) >> 4); | |
v11 = v10 & 0xC | 2 | ((((unsigned __int16)(L1Entry & 0x7000) >> 6) & 0xFF0 | ((L1Entry & 0x38C00) >> 6) & 0xFF0 | ((unsigned __int8)(L1Entry & 0x10) >> 4) & 0xF0) << 6) | (16 * (v10 & 1)); | |
for ( m = 0; m < 0x10; ++m ) | |
{ | |
v13 = (v8 + (m << 20)) | v11; | |
v14 = (v9 + (m << 20)) >> 20; | |
this->L1Table[v14] = v13; | |
} | |
KPageTable::CleanDataCacheRange((u32)&this->L1Table[v9 >> 20], 0x40u); | |
L1Entry = v11 | va & 0xF00000 | v8; | |
goto sectionOnly; | |
} | |
} | |
LABEL_63: | |
if ( size < 0x10000 ) | |
{ | |
v34 = (L1Entry >> 10 << 10) - 0x40000000; | |
if ( (*(_DWORD *)(v34 + ((va & 0xFF000) >> 10)) & 3) == 1 ) | |
{ | |
v35 = *(_DWORD *)(v34 + ((va & 0xFF000) >> 10)) & 0xE3C | ((*(_DWORD *)(v34 + ((va & 0xFF000) >> 10)) & 0x7000u) >> 6) | ((*(_DWORD *)(v34 + ((va & 0xFF000) >> 10)) & 0x8000u) >> 15) | 2; | |
v36 = HIWORD(va) << 16; | |
v37 = HIWORD(*(_DWORD *)(v34 + ((va & 0xFF000) >> 10))) << 16; | |
v38 = 0; | |
v39 = 16; | |
do | |
{ | |
*(_DWORD *)(v34 + (((v36 + (v38 << 12)) & 0xFF000) >> 10)) = (v37 + (v38 << 12)) | v35; | |
--v39; | |
++v38; | |
} | |
while ( v39 ); | |
KPageTable::CleanDataCacheRange(v34 + ((v36 & 0xFF000) >> 10), 0x40u); | |
} | |
} | |
return 0; | |
} | |
//----- (FFF19B3C) -------------------------------------------------------- | |
void __fastcall KPageTable::InvalidateAllTlbEntries(KPageTable *this) | |
{ | |
KTlbMaintenanceHelper *v1; // r9 | |
int coreId; // r12 | |
int i; // r1 | |
KTlbMaintenanceHelperImpl *v4; // r5 | |
unsigned __int8 *p_op; // r2 | |
unsigned __int8 v6; // r6 | |
int v7; // r2 | |
KTlbMaintenanceHelperImpl *v8; // r5 | |
unsigned __int8 *v9; // r2 | |
unsigned __int8 v10; // r6 | |
int v11; // r2 | |
coreId = __mrc(15, 0, 0, 0, 5) & 3; | |
if ( !this->isKernel ) | |
v1 = &g_tlbMaintenanceHelper; | |
i = 0; | |
if ( this->isKernel ) | |
{ | |
while ( 1 ) | |
{ | |
v7 = (MPCORE.scu.cfgr & 3) + 1; | |
if ( v7 <= i ) | |
break; | |
if ( i != coreId ) | |
{ | |
v4 = &g_tlbMaintenanceHelper.impls[i]; | |
while ( 1 ) | |
{ | |
while ( v4->op ) | |
; | |
__disable_irq(); | |
p_op = (unsigned __int8 *)&v4->op; | |
v6 = __ldrex((unsigned __int8 *)&v4->op); | |
if ( v6 ) | |
{ | |
__strex(v6, p_op); | |
} | |
else if ( !__strex(KTLBMAINTOP_INV_ENTIRE_TLB, p_op) ) | |
{ | |
v4->pgTable = this; | |
__mcr(15, 0, 0, 7, 10, 5); | |
MPCORE.gicd.sgir = (1 << i << 16) & 0xFF0000 | 0xA; | |
__enable_irq(); | |
break; | |
} | |
__enable_irq(); | |
} | |
} | |
++i; | |
} | |
__mcr(15, 0, 0, 8, 7, 0); | |
__mcr(15, 0, 0, 7, 10, 4); | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
v11 = (MPCORE.scu.cfgr & 3) + 1; | |
if ( v11 <= i ) // user | |
break; | |
LOBYTE(this->tlbNeedsInvalidating[i]) = 1;// we can postpone the invalidation of TLB of processes that are not currently running | |
if ( v1->currentProcPageTables[i] == this && i != coreId )// if we're the current process | |
{ | |
v8 = &g_tlbMaintenanceHelper.impls[i]; | |
while ( 1 ) | |
{ | |
while ( v8->op ) | |
; | |
__disable_irq(); | |
v9 = (unsigned __int8 *)&v8->op; | |
v10 = __ldrex((unsigned __int8 *)&v8->op); | |
if ( v10 ) | |
{ | |
__strex(v10, v9); | |
} | |
else if ( !__strex(KTLBMAINTOP_INV_ON_ASID_MATCH, v9) ) | |
{ | |
g_tlbMaintenanceHelper.impls[i].pgTable = this; | |
__mcr(15, 0, 0, 7, 10, 5); | |
MPCORE.gicd.sgir = (1 << i << 16) & 0xFF0000 | KINTNAME_SGI_TLB_MAINTENANCE; | |
__enable_irq(); | |
break; | |
} | |
__enable_irq(); | |
} | |
} | |
++i; | |
} | |
if ( v1->currentProcPageTables[coreId] == this ) | |
{ // if we're the current process and this is the current core | |
LOBYTE(this->tlbNeedsInvalidating[coreId]) = 0; | |
__mcr(15, 0, this->asid, 8, 7, 2); | |
__mcr(15, 0, 0, 7, 5, 6); | |
__mcr(15, 0, 0, 7, 10, 4); | |
__mcr(15, 0, 0, 7, 5, 4); | |
} | |
} | |
} | |
// FFF19C18: variable 'v1' is possibly undefined | |
//----- (FFF19CF4) -------------------------------------------------------- | |
KMemoryInfo *__fastcall KMemoryBlock::GetInfo(KMemoryInfo *result, KMemoryBlock *this) | |
{ | |
u32 baseAddr; // r2 | |
u32 numPages; // r3 | |
KMemoryPermission perms; // r12 | |
baseAddr = this->baseAddr; | |
numPages = this->numPages; | |
perms = this->perms; | |
result->state = this->state; | |
result->baseAddress = baseAddr; | |
result->size = numPages << 12; | |
result->perms = perms; | |
return result; | |
} | |
//----- (FFF19D0C) -------------------------------------------------------- | |
void __fastcall KVfpRegisterDumpHelper::DumpAndDisableVfpRegsForCore(s32 coreId) | |
{ | |
KCoreLocalContext *p_clc; // r4 | |
unsigned int *p_threadWithVfp; // r4 | |
KThread *volatile v3; // r5 | |
KThread *volatile threadWithVfp; // t1 | |
KVfpRegisterDumpHelperImpl *v5; // r1 | |
p_clc = &g_coreLocalRegions[coreId].clc; | |
threadWithVfp = p_clc->current.threadWithVfp; | |
p_threadWithVfp = (unsigned int *)&p_clc->current.threadWithVfp; | |
v3 = threadWithVfp; | |
if ( threadWithVfp ) | |
{ | |
if ( (__mrc(15, 0, 0, 0, 5) & 3) == coreId ) | |
{ | |
KThreadContext::EnableCurrentThreadVfp(); | |
KThreadContext::StoreVfpRegsAndDisable(v3->context); | |
KThreadContext::DisableCurrentThreadVfp(); | |
do | |
__ldrex(p_threadWithVfp); | |
while ( __strex(0, p_threadWithVfp) ); | |
} | |
else | |
{ | |
v5 = &g_vfpRegisterDumpHelper.impls[coreId]; | |
v5->threadToDumpTo = v3; | |
__mcr(15, 0, 0, 7, 10, 5); | |
MPCORE.gicd.sgir = (1 << coreId << 16) & 0xFF0000 | KINTNAME_SGI_DUMP_VFP_REGS; | |
while ( v5->threadToDumpTo ) | |
__yield(); | |
} | |
} | |
} | |
//----- (FFF19DCC) -------------------------------------------------------- | |
void __fastcall KDebug::RequestReschedulingForDebugger(KDebug *this, s32 coreId) | |
{ | |
unsigned int CPSR; // r4 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( (__mrc(15, 0, 0, 0, 5) & 3) == coreId ) | |
{ | |
CPSR = __get_CPSR(); | |
__disable_irq(); | |
KScheduler::TrySwitchingThread(current.clc.current.scheduler); | |
__set_CPSR(CPSR); | |
} | |
else | |
{ | |
g_coreLocalRegions[coreId].clc.schedulerInstance.reschedule = 1; | |
current.clc.current.scheduler->triggerSgi = 1; | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
//----- (FFF19E38) -------------------------------------------------------- | |
Result __fastcall KDebug::EmplaceAysncEventInfo( | |
KDebug *this, | |
DebugEventType type, | |
BOOL needsToBeContinued, | |
u32 param1, | |
u32 param2, | |
u32 param3, | |
u32 param4, | |
u32 param5, | |
u32 param6) | |
{ | |
KEventInfo *info; // r0 | |
KEventInfo *v11; // r4 | |
Result result; // r0 | |
KLinkedListNode *v13; // r0 | |
KLinkedListNode *v14; // r0 | |
info = (KEventInfo *)KSlabHeap::Allocate(&g_eventInfoSlabHeap); | |
v11 = info; | |
if ( info ) | |
{ | |
info->isAttachEvent = 0; | |
info->needsToBeContinued = 0; | |
info->ignoreContinue = 0; | |
} | |
result = KDebug::InitalizeAsyncEventInfo(this, type, info, param1, param2, param3, param4, param5, param6); | |
if ( result >= 0 ) | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
v13 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v13 ) | |
{ | |
v13->link.next = 0; | |
v13->link.prev = 0; | |
v13->data = 0; | |
} | |
v13->data = v11; | |
KLinkedList::InsertAfter((KLinkedList *)&this->eventsToFetch, (KLinkedListLink *)&this->eventsToFetch.link, v13); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
if ( (v11->flags & 1) != 0 ) | |
++this->numBlockingEvents; | |
result = needsToBeContinued; | |
if ( needsToBeContinued ) | |
{ | |
v11->needsToBeContinued = 1; | |
v11->isProcessed = 0; | |
KSchedulerLock::Lock(&g_schedulerLock); | |
v14 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v14 ) | |
{ | |
v14->link.next = 0; | |
v14->link.prev = 0; | |
v14->data = 0; | |
} | |
v14->data = v11; | |
KLinkedList::InsertAfter( | |
(KLinkedList *)&this->eventsToContinue, | |
(KLinkedListLink *)&this->eventsToContinue.link, | |
v14); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
} | |
return result; | |
} | |
// FFF19E70: conditional instruction was optimized away because r0.4!=0 | |
// FFF19EDC: conditional instruction was optimized away because r0.4!=0 | |
// FFF19F84: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF19FCC) -------------------------------------------------------- | |
Result __fastcall KDebug::BreakCurrentProcess(KDebug *this, KThread *thread) | |
{ | |
int pausingCurrentThreads; // r7 | |
KDebugThreadLinkedListNode *node; // r4 | |
KDebugThread *breakThread; // r2 | |
KThread *v7; // r1 | |
bool v8; // zf | |
KDebugThreadLinkedListNode *i; // r4 | |
KThread *v10; // r1 | |
KDebugThread *debugThread; // r0 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
pausingCurrentThreads = 0; | |
this->breakThread = thread; | |
KDebug::BuildOrderedListOfThreads(this); | |
for ( node = this->debugThreads.link.next; | |
node != (KDebugThreadLinkedListNode *)&this->debugThreads.link; | |
node = node->link.next ) | |
{ | |
breakThread = (KDebugThread *)this->breakThread; | |
v7 = node->debugThread->thread; | |
v8 = breakThread == (KDebugThread *)v7; | |
if ( breakThread != (KDebugThread *)v7 ) // not attached or not the break thread | |
{ | |
breakThread = v7->debugThread; | |
v8 = breakThread == 0; | |
} | |
if ( !v8 ) | |
{ | |
if ( *(KThread **)(0x9000 * v7->coreId + 0xFFFD1000) == v7 )// don't pause the current threads now | |
{ | |
pausingCurrentThreads = 1; | |
} | |
else | |
{ | |
breakThread->debugBreakPauseRequested = 1; | |
KDebug::RequestPause(this, v7); | |
} | |
} | |
} | |
if ( pausingCurrentThreads ) // pause them now | |
{ | |
for ( i = this->debugThreads.link.next; i != (KDebugThreadLinkedListNode *)&this->debugThreads.link; i = i->link.next ) | |
{ | |
v10 = i->debugThread->thread; | |
if ( (v10->schedulingMask & 0x80) == 0 && this->breakThread != v10 ) | |
{ | |
debugThread = v10->debugThread; | |
if ( debugThread ) | |
{ | |
debugThread->debugBreakPauseRequested = 1; | |
KDebug::RequestPause(this, v10); | |
} | |
} | |
} | |
KScheduler::TriggerSgi(current.clc.current.scheduler); | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
//----- (FFF1A0E8) -------------------------------------------------------- | |
Result __fastcall KDebug::UnbreakCurrentProcess(KDebug *this) | |
{ | |
KDebug *node; // r4 | |
KThread *count; // r0 | |
KDebugThread *debugThread; // r1 | |
bool v5; // zf | |
KThreadLinkedListNode *v6; // r10 | |
KLinkedListLink *v7; // r0 | |
KLinkedListLink *v8; // r8 | |
KDebugThreadLinkedListNode *i; // r4 | |
KThread *thread; // r0 | |
KDebugThread *schedulingMask; // r1 | |
bool v12; // zf | |
KDebugThreadLinkedListNode *j; // r0 | |
KDebugThread *v14; // r1 | |
bool v15; // zf | |
KThreadLinkedListNode *next; // [sp+0h] [bp-28h] BYREF | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( this->breakThread ) | |
{ | |
for ( node = (KDebug *)this->orderedThreadListForBreak.link.next; | |
node != (KDebug *)&this->orderedThreadListForBreak.link; | |
node = (KDebug *)node->KSynchronizationObject::KAutoObject::__vftable ) | |
{ | |
count = (KThread *)node->waiters.count; | |
debugThread = count->debugThread; | |
v5 = debugThread == 0; | |
if ( debugThread ) | |
v5 = !debugThread->debugBreakPauseRequested; | |
if ( !v5 ) | |
{ | |
debugThread->debugBreakPauseRequested = 0; | |
count->debugThread->debugPauseRequested = 0; | |
KThread::SetDebugPauseState(count, 0); | |
} | |
} | |
next = this->orderedThreadListForBreak.link.next; | |
if ( next != (KThreadLinkedListNode *)&this->orderedThreadListForBreak.link ) | |
{ | |
do | |
{ | |
v6 = next; | |
KLinkedList::EraseNode((KLinkedList *)&this->orderedThreadListForBreak, (KLinkedListLink **)&next); | |
v8 = v7; | |
KSlabHeap::Free(&g_linkedListNodeSlabHeap, v6); | |
next = (KThreadLinkedListNode *)v8; | |
} | |
while ( v8 != (KLinkedListLink *)&this->orderedThreadListForBreak.link ); | |
} | |
for ( i = this->debugThreads.link.next; i != (KDebugThreadLinkedListNode *)&this->debugThreads.link; i = i->link.next )// also inspect new threads | |
{ | |
thread = i->debugThread->thread; | |
schedulingMask = (KDebugThread *)thread->schedulingMask; | |
v12 = (unsigned __int8)((unsigned __int8)schedulingMask & KTHREADSCHEDSTAT_DEBUG_PAUSE_FLAG) == 0; | |
if ( ((unsigned __int8)schedulingMask & (unsigned __int8)KTHREADSCHEDSTAT_DEBUG_PAUSE_FLAG) != 0 ) | |
{ | |
schedulingMask = thread->debugThread; | |
v12 = schedulingMask == 0; | |
} | |
if ( !v12 ) | |
v12 = !schedulingMask->debugBreakPauseRequested; | |
if ( !v12 ) | |
{ | |
schedulingMask->debugPauseRequested = 0; | |
KThread::SetDebugPauseState(thread, 0); | |
} | |
} | |
for ( j = this->debugThreads.link.next; j != (KDebugThreadLinkedListNode *)&this->debugThreads.link; j = j->link.next ) | |
{ | |
v14 = j->debugThread->thread->debugThread; | |
v15 = v14 == 0; | |
if ( v14 ) | |
v15 = !v14->debugBreakPauseRequested; | |
if ( !v15 ) | |
v14->debugBreakPauseRequested = 0; | |
} | |
this->breakThread = 0; | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
// FFF1A184: variable 'v7' is possibly undefined | |
//----- (FFF1A254) -------------------------------------------------------- | |
Result __fastcall KThread::SetPriority(KThread *this, s32 priority) | |
{ | |
KMutexIntrusiveLinkPtr p_link; // r0 | |
s32 basePriority; // r0 | |
s32 dynamicPriority; // r2 | |
KMutexLinkedListNode *node; // r4 | |
KMutexLinkedListLink *v9; // r5 | |
KMutexLinkedListNode *next; // t1 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( (unsigned int)priority < 0x40 ) | |
{ | |
if ( this->priorityToRestoreAfterSleep == -1 ) | |
{ | |
this->basePriority = priority; | |
p_link = &ADJ(this->heldMutexListRootNode)->link;// thread is holding 1 or more KMutex | |
if ( p_link ) | |
basePriority = ADJ(p_link)->priority; | |
else | |
basePriority = 63; | |
dynamicPriority = this->dynamicPriority; | |
if ( this->basePriority <= basePriority ) | |
basePriority = this->basePriority; | |
if ( dynamicPriority != basePriority ) | |
{ | |
this->dynamicPriority = basePriority; | |
KScheduler::AdjustThreadPriorityChanged(current.clc.current.scheduler, this, dynamicPriority); | |
} | |
next = this->mutexTryingToAcquireList.link.next; | |
v9 = &this->mutexTryingToAcquireList.link; | |
for ( node = next; node != (KMutexLinkedListNode *)v9; node = node->link.next ) | |
KMutex::RecalculatePriority(node->mutex); | |
} | |
else | |
{ | |
this->priorityToRestoreAfterSleep = priority; | |
} | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0; | |
} | |
else | |
{ | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return 0xD8E007FD; | |
} | |
} | |
//----- (FFF1A318) -------------------------------------------------------- | |
s32 __fastcall KResourceLimit::GetLimitValue(KResourceLimit *this, ResourceLimitType type) | |
{ | |
return this->limitValues[type]; | |
} | |
//----- (FFF1A324) -------------------------------------------------------- | |
s32 __fastcall KDmaAddress::GetPhysicalChunkSize(KDmaAddress *this, s32 size) | |
{ | |
u32 currentPa; // r9 | |
s32 chunkSize; // r8 | |
KProcess *process; // r1 | |
u32 currentVa; // r6 | |
KProcessPageTable *p_pgTable; // r4 | |
unsigned int v8; // r2 | |
bool v9; // zf | |
unsigned int v11; // r2 | |
bool v12; // zf | |
int v13; // r5 | |
u32 v14; // r0 | |
KProcessPageTable *pgTable; // [sp+0h] [bp-40h] | |
KTranslationTableTraversalContext v16; // [sp+8h] [bp-38h] BYREF | |
KTranslationTableIterator it; // [sp+10h] [bp-30h] BYREF | |
KTranslationTableIterator node; // [sp+18h] [bp-28h] | |
int v19; // [sp+20h] [bp-20h] | |
chunkSize = 0; | |
if ( this->isDevice || !size ) // "device" bypass checks again | |
return size; | |
currentVa = this->currentVa; | |
if ( size <= 0 ) | |
currentPa = this->currentPa; | |
process = this->process; | |
p_pgTable = &process->pgTable; | |
if ( size <= 0 ) | |
{ | |
while ( 1 ) | |
{ | |
v13 = ((currentPa - 1) & 0xFFF) + 1; | |
chunkSize -= v13; | |
if ( size >= chunkSize ) | |
break; | |
v14 = KPageTable::ConvertVaToPa(&p_pgTable->L1Table, currentVa + chunkSize); | |
if ( currentPa - v13 != v14 ) | |
return chunkSize; | |
currentPa = v14; | |
} | |
return size; | |
} | |
else | |
{ | |
v19 = 0; | |
pgTable = &process->pgTable; | |
v8 = __ldrex((unsigned int *)p_pgTable); | |
v9 = v8 == 0; | |
if ( v8 ) | |
__strex(v8, (unsigned int *)p_pgTable); | |
else | |
v8 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)p_pgTable); | |
if ( v9 ) | |
v9 = v8 == 0; | |
if ( !v9 ) | |
KLightMutex::LockImpl(&p_pgTable->mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KTranslationTableIterator::CreateFromEntry(&p_pgTable->L1Table, &it, &v16, currentVa); | |
__mcr(15, 0, 0, 7, 10, 5); | |
p_pgTable->mutex.lockingThread = 0; | |
if ( p_pgTable->mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&p_pgTable->mutex); | |
node.size = 0; | |
if ( !it.pa ) | |
return 0; | |
it.size -= (it.size - 1) & currentVa; | |
for ( node = it; node.size + v19 < size; node.size += it.size ) | |
{ | |
v11 = __ldrex((unsigned int *)pgTable); | |
v12 = v11 == 0; | |
if ( v11 ) | |
__strex(v11, (unsigned int *)pgTable); | |
else | |
v11 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)pgTable); | |
if ( v12 ) | |
v12 = v11 == 0; | |
if ( !v12 ) | |
KLightMutex::LockImpl(&pgTable->mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
KTranslationTableIterator::Advance(&pgTable->L1Table, &it, &v16); | |
__mcr(15, 0, 0, 7, 10, 5); | |
pgTable->mutex.lockingThread = 0; | |
if ( pgTable->mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&pgTable->mutex); | |
if ( !it.pa ) | |
{ | |
v19 = 0; | |
return node.size; | |
} | |
if ( node.pa + node.size != it.pa ) | |
return node.size; | |
} | |
if ( v19 != size ) | |
node.size = size - v19; | |
return node.size; | |
} | |
} | |
// FFF1A3F8: conditional instruction was optimized away because %var_3C.4>=1 | |
// FFF1A4E4: variable 'currentPa' is possibly undefined | |
//----- (FFF1A530) -------------------------------------------------------- | |
void __fastcall KPageGroup::AddRange(KPageGroup *this, u32 addr, u32 numPages) | |
{ | |
bool v6; // zf | |
KBlockInfo *blockInfo; // r0 | |
u32 v8; // r1 | |
KBlockInfo *v9; // r4 | |
KLinkedListNode *v10; // r0 | |
KSchedulerLock::Lock(&g_schedulerLock); | |
v6 = numPages == 0; | |
if ( numPages ) | |
v6 = addr + (numPages << 12) == 0; | |
if ( v6 ) | |
goto LABEL_9; | |
if ( this->list.count ) | |
{ | |
blockInfo = this->list.link.prev->blockInfo;// coaelse with last, otherwise append | |
v8 = blockInfo->numPages; | |
if ( blockInfo->baseAddress + (v8 << 12) == addr ) | |
{ | |
if ( addr ) | |
{ | |
blockInfo->numPages = v8 + numPages; | |
LABEL_9: | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
return; | |
} | |
} | |
} | |
v9 = (KBlockInfo *)KSlabHeap::Allocate(&g_blockInfoSlabHeap); | |
v9->numPages = numPages; | |
v9->baseAddress = addr; | |
v10 = (KLinkedListNode *)KSlabHeap::Allocate(&g_linkedListNodeSlabHeap); | |
if ( v10 ) | |
{ | |
v10->link.next = 0; | |
v10->link.prev = 0; | |
v10->data = 0; | |
} | |
v10->data = v9; | |
KLinkedList::InsertAfter((KLinkedList *)this, (KLinkedListLink *)&this->list.link, v10); | |
KSchedulerLock::Unlock(&g_schedulerLock); | |
} | |
// FFF1A5F0: conditional instruction was optimized away because r0.4!=0 | |
//----- (FFF1A62C) -------------------------------------------------------- | |
Result __fastcall KPageTable::QueryInfo(KPageTable *this, KMemoryInfo *outMemoryInfo, u32 *pageInfo, u32 addr) | |
{ | |
unsigned int v8; // r2 | |
bool v9; // zf | |
unsigned int v10; // r3 | |
KMemoryBlock *MemoryBlockContainingAddr; // r0 | |
bool v12; // zf | |
u32 size; // r1 | |
KMemoryPermission perms; // r2 | |
KMemoryState state; // r3 | |
Result v16; // r5 | |
KMemoryInfo v18; // [sp+0h] [bp-30h] BYREF | |
v8 = __ldrex((unsigned int *)this); | |
v9 = v8 == 0; | |
if ( v8 ) | |
v10 = __strex(v8, (unsigned int *)this); | |
else | |
v10 = __strex((unsigned int)current.clc.current.thread, (unsigned int *)this); | |
if ( !v8 ) | |
v9 = v10 == 0; | |
if ( !v9 ) | |
KLightMutex::LockImpl(&this->mutex); | |
__mcr(15, 0, 0, 7, 10, 5); | |
MemoryBlockContainingAddr = KMemoryBlockManager::GetMemoryBlockContainingAddr(&this->memoryBlockMgr, addr); | |
v12 = outMemoryInfo == 0; | |
if ( outMemoryInfo ) | |
v12 = MemoryBlockContainingAddr == 0; | |
if ( v12 ) | |
{ | |
KMemoryBlockManager::DumpInfoMaybe_stubbed(&this->memoryBlockMgr); | |
v16 = 0xE0E01BF5; | |
} | |
else | |
{ | |
KMemoryBlock::GetInfo(&v18, MemoryBlockContainingAddr); | |
size = v18.size; | |
perms = v18.perms; | |
state = v18.state; | |
outMemoryInfo->baseAddress = v18.baseAddress; | |
outMemoryInfo->size = size; | |
outMemoryInfo->perms = perms; | |
outMemoryInfo->state = state; | |
v16 = 0; | |
*pageInfo = 0; | |
} | |
__mcr(15, 0, 0, 7, 10, 5); | |
this->mutex.lockingThread = 0; | |
if ( this->mutex.numWaiters > 0 ) | |
KLightMutex::UnlockImpl(&this->mutex); | |
return v16; | |
} | |
//----- (FFF1A6E0) -------------------------------------------------------- | |
void __fastcall KScheduler::AddThread(KScheduler *this, KThread *thread) | |
{ | |
int coreId; // r5 | |
s32 prio; // r3 | |
KScheduler *sched; // r2 | |
KThreadIntrusiveLink *p_link; // r12 | |
KThread *prev; // r4 | |
BOOL v7; // r7 | |
KThreadIntrusiveLink *v8; // r8 | |
int v9; // r12 | |
int v10; // r3 | |
coreId = this->coreId; // next = first, prev = last | |
prio = thread->dynamicPriority; | |
sched = &g_coreLocalRegions[thread->coreId].clc.schedulerInstance; | |
p_link = &sched->threadsByPrio[prio].link; | |
prev = p_link->prev; | |
v7 = sched->threadsByPrio[prio].link.next == 0; | |
if ( p_link->prev ) | |
v8 = &prev->link; | |
else | |
v8 = &sched->threadsByPrio[prio].link; | |
thread->link.prev = prev; | |
thread->link.next = 0; | |
v8->next = thread; | |
p_link->prev = thread; | |
__mcr(15, 0, 0, 7, 10, 5); | |
if ( v7 ) | |
sched->prioBitfield[(unsigned int)prio >> 5] |= 0x80000000 >> (prio & 0x1F); | |
v9 = sched->coreId; | |
++sched->numThreads; | |
if ( v9 != coreId || current.clc.current.thread->dynamicPriority > prio ) | |
{ | |
v10 = sched->coreId; | |
sched->reschedule = 1; | |
if ( v10 != coreId ) | |
this->triggerSgi = 1; | |
} | |
} | |
//----- (FFF1A7B4) -------------------------------------------------------- | |
void __fastcall KScheduler::RescheduleByForce(KScheduler *this, KThread *forcedThread) | |
{ | |
this->reschedule = 1; | |
KScheduler::SwitchThread(this, forcedThread); | |
} | |
//----- (FFF1A7C0) -------------------------------------------------------- | |
void __fastcall KScheduler::SwitchThread(KScheduler *this, KThread *forcedThread) | |
{ | |
int v2; // r4 | |
int v3; // r5 | |
int v4; // r6 | |
int v5; // r7 | |
int v6; // r8 | |
int v7; // r9 | |
int v8; // r10 | |
int v9; // r11 | |
int v10; // lr | |
_DWORD *v11; // r2 | |
KThreadContext *v17; // r0 | |
KScheduler *v18; // r2 | |
KScheduler *v19; // [sp-8h] [bp-8h] | |
int v20; // [sp+0h] [bp+0h] BYREF | |
if ( this->reschedule ) | |
{ | |
this->reschedule = 0; | |
this->disableCount = 1; | |
__enable_irq(); | |
v11 = (_DWORD *)(((((unsigned int)&v20 >> 12) + 1) << 12) - 176); | |
*v11 = v2; | |
v11[1] = v3; | |
v11[2] = v4; | |
v11[3] = v5; | |
v11[4] = v6; | |
v11[5] = v7; | |
v11[6] = v8; | |
v11[7] = v9; | |
v11[8] = &v20; | |
v11[9] = v10; | |
__asm { VMRS R3, FPEXC } | |
v11[42] = _R3; | |
v19 = this; | |
while ( 1 ) | |
{ | |
v17 = KScheduler::Reschedule(this, forcedThread); | |
v18 = v19; | |
if ( v17 ) | |
KThreadContext::Load(v17); | |
__disable_irq(); | |
if ( !v18->reschedule ) | |
break; | |
v18->reschedule = 0; | |
__enable_irq(); | |
v19 = v18; | |
this = v18; | |
forcedThread = 0; | |
} | |
v18->disableCount = 0; | |
} | |
} | |
// FFF1A7EC: variable 'v2' is possibly undefined | |
// FFF1A7EC: variable 'v3' is possibly undefined | |
// FFF1A7EC: variable 'v4' is possibly undefined | |
// FFF1A7EC: variable 'v5' is possibly undefined | |
// FFF1A7EC: variable 'v6' is possibly undefined | |
// FFF1A7EC: variable 'v7' is possibly undefined | |
// FFF1A7EC: variable 'v8' is possibly undefined | |
// FFF1A7EC: variable 'v9' is possibly undefined | |
// FFF1A7EC: variable 'v10' is possibly undefined | |
// FFF1A810: variable 'v18' is possibly undefined | |
//----- (FFF1A83C) -------------------------------------------------------- | |
Result __fastcall KPageTable::CopyMemoryInterprocessForIpc( | |
KPageTable *this, | |
u32 dstAddr, | |
KPageTable *srcPgTbl, | |
u32 srcAddr, | |
u32 size) | |
{ | |
int v7; // r6 | |
bool v8; // zf | |
KCopyMemoryForIpcHelper *p_srcHelper; // r4 | |
u32 v11; // r2 | |
u32 v12; // r0 | |
KTranslationTableIterator v13; // [sp+0h] [bp-50h] BYREF | |
KCopyMemoryForIpcHelper srcHelper; // [sp+Ch] [bp-44h] BYREF | |
KTranslationTableIterator ttblIterator; // [sp+20h] [bp-30h] BYREF | |
KCopyMemoryForIpcHelper dstHelper; // [sp+28h] [bp-28h] BYREF | |
dstHelper.pgTblPtr = this; | |
KTranslationTableIterator::CreateFromEntry(&this->L1Table, &v13, &dstHelper.traversalContext, dstAddr); | |
dstHelper.pa = v13.pa; | |
dstHelper.size = v13.size - ((v13.size - 1) & v13.pa); | |
srcHelper.pgTblPtr = srcPgTbl; | |
KTranslationTableIterator::CreateFromEntry(&srcPgTbl->L1Table, &v13, &srcHelper.traversalContext, srcAddr); | |
v7 = 0; | |
srcHelper.pa = v13.pa; | |
srcHelper.size = v13.size - (v13.pa & (v13.size - 1)); | |
v8 = dstHelper.pa == 0; | |
if ( dstHelper.pa ) | |
v8 = srcHelper.pa == 0; | |
if ( v8 ) | |
{ | |
if ( size ) | |
return 0xE0A01BF5; | |
else | |
return 0; | |
} | |
else | |
{ | |
while ( 1 ) | |
{ | |
if ( dstHelper.size > srcHelper.size ) | |
p_srcHelper = &srcHelper; | |
else | |
p_srcHelper = &dstHelper; | |
if ( dstHelper.size <= srcHelper.size ) | |
srcAddr = (u32)&srcHelper; | |
if ( dstHelper.size > srcHelper.size ) | |
srcAddr = (u32)&dstHelper; | |
if ( p_srcHelper->size + v7 >= size ) | |
break; | |
KTranslationTableIterator::Advance(&p_srcHelper->pgTblPtr->L1Table, &ttblIterator, &p_srcHelper->traversalContext); | |
v11 = p_srcHelper->size; | |
if ( p_srcHelper->pa + v11 == ttblIterator.pa ) | |
{ | |
p_srcHelper->size = ttblIterator.size + v11; | |
} | |
else | |
{ | |
memcpy((void *)(dstHelper.pa + 0xC0000000), (const void *)(srcHelper.pa + 0xC0000000), v11); | |
v12 = p_srcHelper->size; | |
*(_DWORD *)(srcAddr + 12) += v12; | |
v7 += v12; | |
*(_DWORD *)(srcAddr + 16) -= p_srcHelper->size; | |
*(KTranslationTableIterator *)&p_srcHelper->pa = ttblIterator; | |
} | |
} | |
memcpy((void *)(dstHelper.pa + 0xC0000000), (const void *)(srcHelper.pa + 0xC0000000), size - v7); | |
return 0; | |
} | |
} | |
//----- (FFF1A9CC) -------------------------------------------------------- | |
void *__fastcall memcpy(void *dst, const void *src, u32 size) | |
{ | |
int v3; // r3 | |
unsigned int v4; // r12 | |
char v5; // r3 | |
char v6; // t1 | |
bool v7; // cf | |
bool v8; // cc | |
u32 v9; // r2 | |
char v10; // t1 | |
char v11; // t1 | |
bool v12; // cf | |
u32 v13; // r2 | |
int *v14; // r1 | |
int v15; // t1 | |
int v16; // t1 | |
int v17; // t1 | |
bool v18; // cf | |
bool v19; // nf | |
signed __int32 v20; // r2 | |
char *v21; // r1 | |
char v22; // t1 | |
char v23; // t1 | |
char *v24; // r0 | |
if ( size > 3 ) | |
{ | |
v4 = (unsigned __int8)dst & 3; | |
if ( ((unsigned __int8)dst & 3) != 0 ) | |
{ | |
v6 = *(_BYTE *)src; | |
src = (char *)src + 1; | |
v5 = v6; | |
v7 = v4 >= 2; | |
v8 = v4 > 2; | |
v9 = size + v4; | |
if ( ((unsigned __int8)dst & 3) != 3 ) | |
{ | |
v10 = *(_BYTE *)src; | |
src = (char *)src + 1; | |
LOBYTE(v4) = v10; | |
} | |
*(_BYTE *)dst = v5; | |
dst = (char *)dst + 1; | |
if ( !v7 ) | |
{ | |
v11 = *(_BYTE *)src; | |
src = (char *)src + 1; | |
v5 = v11; | |
} | |
if ( !v8 ) | |
{ | |
*(_BYTE *)dst = v4; | |
dst = (char *)dst + 1; | |
} | |
size = v9 - 4; | |
if ( !v7 ) | |
{ | |
*(_BYTE *)dst = v5; | |
dst = (char *)dst + 1; | |
} | |
} | |
LOBYTE(v3) = (unsigned __int8)src & 3; | |
if ( ((unsigned __int8)src & 3) == 0 ) | |
return qmemcpy(dst, src, size); | |
v12 = size >= 8; | |
v13 = size - 8; | |
while ( v12 ) | |
{ | |
v15 = *(_DWORD *)src; | |
v14 = (int *)((char *)src + 4); | |
v3 = v15; | |
v12 = v13 >= 8; | |
v13 -= 8; | |
v16 = *v14; | |
src = v14 + 1; | |
LOBYTE(v4) = v16; | |
*(_DWORD *)dst = v3; | |
*((_DWORD *)dst + 1) = v16; | |
dst = (char *)dst + 8; | |
} | |
size = v13 + 4; | |
if ( (size & 0x80000000) == 0 ) | |
{ | |
v17 = *(_DWORD *)src; | |
src = (char *)src + 4; | |
LOBYTE(v3) = v17; | |
*(_DWORD *)dst = v17; | |
dst = (char *)dst + 4; | |
} | |
} | |
v18 = __CFSHL__(size, 31); | |
v20 = size << 31; | |
v19 = v20 < 0; | |
if ( v18 ) | |
{ | |
v22 = *(_BYTE *)src; | |
v21 = (char *)src + 1; | |
LOBYTE(v3) = v22; | |
v23 = *v21; | |
src = v21 + 1; | |
LOBYTE(v4) = v23; | |
} | |
if ( v20 < 0 ) | |
LOBYTE(v20) = *(_BYTE *)src; | |
if ( v18 ) | |
{ | |
*(_BYTE *)dst = v3; | |
v24 = (char *)dst + 1; | |
*v24 = v4; | |
dst = v24 + 1; | |
} | |
if ( v19 ) | |
{ | |
*(_BYTE *)dst = v20; | |
return (char *)dst + 1; | |
} | |
return dst; | |
} | |
// FFF1AA44: variable 'v3' is possibly undefined | |
// FFF1AA48: variable 'v4' is possibly undefined | |
//----- (FFF1AA54) -------------------------------------------------------- | |
void __fastcall KCacheMaintenanceHelper::RequestOtherCoresCacheMaintenanceByMva( | |
bool *outAsync, | |
KCacheMaintenanceOperation op, | |
u32 addr, | |
u32 size) | |
{ | |
__int64 v4; // r8 | |
bool v5; // cc | |
bool v6; // r10 | |
KThread *volatile thread; // r5 | |
KThreadIntrusiveList *p_waitList; // r7 | |
KThreadIntrusiveList *p_link; // r1 | |
KThreadIntrusiveLink link; // r0 | |
KThreadIntrusiveList *v11; // r2 | |
char cfgr; // r1 | |
unsigned __int8 v13; // r1 | |
int v14; // r3 | |
KCacheMaintenanceOperation v15; // [sp+0h] [bp-38h] | |
LODWORD(v4) = addr; | |
HIDWORD(v4) = size; | |
v5 = (unsigned __int8)g_kernelState > KSTATE_INITIALIZING; | |
if ( g_kernelState != KSTATE_INITIALIZING ) | |
v5 = size - addr > 0x200; | |
v6 = v5; | |
*outAsync = v6; | |
v15 = op | 4; | |
thread = current.clc.current.thread; | |
while ( 1 ) | |
{ | |
KSchedulerLock::Lock(&g_schedulerLock); | |
if ( g_cacheMaintenanceHelper.op == KCACHEMAINTOP_NONE ) | |
break; | |
p_waitList = &g_cacheMaintenanceHelper.waitList; | |
thread->waiterList = &g_cacheMaintenanceHelper.waitList; | |
KThread::SetSchedulingState(thread, KTHREADSCHEDSTAT_PAUSED); | |
if ( g_cacheMaintenanceHelper.waitList.link.prev ) | |
p_link = (KThreadIntrusiveList *)&g_cacheMaintenanceHelper.waitList.link.prev->link; | |
else | |
p_link = &g_cacheMaintenanceHelper.waitList; | |
thread->link.prev = g_cacheMaintenanceHelper.waitList.link.prev; | |
thread->link.next = 0; | |
p_link->link.next = thread; | |
g_cacheMaintenanceHelper.waitList.link.prev = thread; | |
if ( thread->shallTerminate ) | |
{ | |
link = thread->link; | |
if ( link.prev ) | |
v11 = (KThreadIntrusiveList *)&link.prev->link; | |
else | |
v11 = &g_cacheMaintenanceHelp |
View raw
(Sorry about that, but we can’t show files that are this big right now.)
View raw
(Sorry about that, but we can’t show files that are this big right now.)
View raw
(Sorry about that, but we can’t show files that are this big right now.)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment