-
-
Save TuxSH/32bfd1f0952507e111939cb7acca920e to your computer and use it in GitHub Desktop.
PTM sleep state machine
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
void __fastcall SleepLoop(ModeControlManager *this) | |
{ | |
void (*v2)(void); // r0 | |
void (__cdecl *v3)(_DWORD); // r0 | |
u32 v4; // r0 | |
u32 *offset0x1C0; // r1 | |
__int64 v6; // r0 | |
int wakeupMask; // r5 | |
WakeupTriggerEntry *v8; // r12 | |
WakeupTriggerEntry *v9; // r0 | |
int v10; // lr | |
u32 v11; // r3 | |
int v12; // r1 | |
int v13; // r2 | |
u64 v14; // r6 | |
signed int v15; // r1 | |
u64 v16; // r0 | |
u64 mcuReadWakeFlags; // r6 | |
u32 v18; // r6 | |
u64 v19; // r0 | |
u64 v20; // r0 | |
u64 v21; // r0 | |
u64 v22; // r0 | |
u64 v23; // r0 | |
int v24; // r1 | |
void (__cdecl *v25)(_DWORD, int); // r0 | |
void (*v26)(void); // r0 | |
void (*v27)(void); // r0 | |
s32 v28; // r1 | |
int v29; // r0 | |
u32 v30; // r0 | |
u64 v31; // r0 | |
u64 v32; // r0 | |
u64 v33; // r0 | |
RecursiveLock *v34; // [sp+0h] [bp-60h] | |
char v35; // [sp+4h] [bp-5Ch] | |
Handle *v36; // [sp+8h] [bp-58h] | |
u32 resumeSleepMaskMcu; // [sp+Ch] [bp-54h] | |
int resumeSleepMask; // [sp+10h] [bp-50h] | |
int v39; // [sp+14h] [bp-4Ch] | |
int wakeupMaskMcu; // [sp+1Ch] [bp-44h] | |
u32 newMcuIrqMask; // [sp+20h] [bp-40h] | |
u32 *offset0x1C0_2; // [sp+24h] [bp-3Ch] | |
int offset0x180; // [sp+28h] [bp-38h] | |
u32 *v44; // [sp+2Ch] [bp-34h] | |
int doingSleep; // [sp+30h] [bp-30h] | |
u32 mask; // [sp+34h] [bp-2Ch] | |
WakeupTriggerEntry *v47; // [sp+38h] [bp-28h] | |
u32 allWakeFlags; // [sp+3Ch] [bp-24h] | |
int v49; // [sp+40h] [bp-20h] | |
Handle *handle; // [sp+44h] [bp-1Ch] | |
LOBYTE(v34) = 1; | |
v36 = (Handle *)((char *)&this->pxiMcHandle + 3); | |
this->sleepAllowed = 1; | |
this->sleepState = 1; | |
PublishAndGetSleepSubscribers(this, 0x101u, 3u); | |
WaitSleepPreparationCompleteAll(this); | |
if ( this->sleepAllowed ) // ReplySleepQuery may have changed this field | |
{ | |
this->sleepState = 2; | |
PublishAndGetSleepSubscribers(this, 0x103u, 1u); | |
WaitSleepPreparationCompleteAll(this); | |
svcKernelSetState(5u, 1); // pause all processes that don't have "RunnableInSleep" | |
*((_BYTE *)v36 + 8) = 3; // ->sleepState = 3 | |
v34 = &this->mcuLock; | |
RecursiveLock_LockImpl(&this->mcuLock); | |
this->numWakeupTriggers = 0; | |
PublishAndGetSleepSubscribers(this, 0x104u, 0); | |
offset0x180 = (int)&this->subscribers[57]; | |
v2 = this->onSleepTransition3_changeLeds; // change led brightness and power led pattern | |
if ( v2 ) | |
v2(); | |
LightEvent_Signal((LightEvent *)&dword_10E300); | |
RecursiveLock_LockImpl((RecursiveLock *)&unk_110E14); | |
WaitSleepPreparationCompleteAll(this); | |
v3 = *(void (__cdecl **)(_DWORD))&this->onSleepTransition4_shittyTimeStuff; | |
if ( v3 ) | |
v3(v3); | |
v35 = 4; | |
doingSleep = 1; | |
this->sleepState = 4; | |
MCURTC_EnterExclusiveMode(&this->mcuRtcHandle);// prevent mcu sysmodule from handling mcu interrupts | |
resumeSleepMaskMcu = 0; | |
MCURTC_ReceiveInterruptBits(&this->mcuRtcHandle, &resumeSleepMaskMcu);// the ones that mcu sysmodule hasn't yet handled | |
v4 = resumeSleepMaskMcu; | |
offset0x1C0 = &this->updateSharedTimeOnWakeupCallBack; | |
offset0x1C0_2 = offset0x1C0; | |
offset0x1C0[4] = 0; // already received, not handled mcu interrupts | |
offset0x1C0[5] = v4; | |
RecursiveLock_Unlock(&v34); | |
v47 = this->wakeupTriggers; | |
v44 = &this->unk_40; | |
do | |
{ | |
HIDWORD(v6) = offset0x1C0_2[4]; // @0x1d0 | |
LODWORD(v6) = offset0x1C0_2[5]; | |
v39 = 0; | |
if ( !v6 ) | |
{ // don't go to sleep if mcu interrupt | |
// otherwise make k9 wfi until it receives a new pxi sync irq, and prevent pxi sysmodule to send anything but this command | |
ModeControlManager::SleepPxi(this, 1); | |
v39 = 1; | |
} | |
wakeupMask = 0; | |
resumeSleepMask = 0; | |
wakeupMaskMcu = 0; | |
resumeSleepMaskMcu = 0; | |
v8 = &this->wakeupTriggers[*((unsigned __int16 *)offset0x1C0_2 + 12)]; | |
v9 = v47; | |
while ( v9 < v8 ) | |
{ | |
v10 = LODWORD(v9->wakeupMask) | wakeupMask; | |
v11 = HIDWORD(v9->resumeSleepMask) | resumeSleepMaskMcu; | |
v12 = HIDWORD(v9->wakeupMask) | wakeupMaskMcu; | |
v13 = LODWORD(v9->resumeSleepMask) | resumeSleepMask; | |
++v9; | |
wakeupMask = v10; | |
resumeSleepMaskMcu = v11; | |
resumeSleepMask = v13; | |
wakeupMaskMcu = v12; | |
} | |
HIDWORD(v14) = wakeupMaskMcu | resumeSleepMaskMcu; | |
LODWORD(v14) = wakeupMask | resumeSleepMask; | |
if ( 4 * (wakeupMaskMcu | resumeSleepMaskMcu) >> 2 )// ignore power button mcuirqs when considering this | |
v15 = 0x4000000; // mcu | |
else | |
v15 = 0; | |
newMcuIrqMask = wakeupMaskMcu | resumeSleepMaskMcu; | |
allWakeFlags = v14 | v15; | |
PDNS_SetWakeEvents(v14 | v15, 0xFFFFFFFF); | |
v16 = SyncMcuIrqBitmaskWithWakeEvents(this, v14);// check shell state/adapter state/battery state, | |
// we may have to "wake up" even before going to sleep | |
mcuReadWakeFlags = *((_QWORD *)offset0x1C0_2 + 2) | v16;// 1d0 | |
if ( !mcuReadWakeFlags ) // check if we woke up before going to sleep... | |
{ | |
MCURTC_GetInterruptMask(&this->mcuRtcHandle, &mask); | |
MCURTC_SetInterruptMask(&this->mcuRtcHandle, newMcuIrqMask); | |
MCURTC_WriteReg20Bit4_SleepMaybe(&this->mcuRtcHandle); | |
LOBYTE(v34) = 5; | |
this->sleepState = 5; | |
svcKernelSetState(2u, 0); // actually go to sleep | |
LOBYTE(v34) = 6; | |
*((_BYTE *)v36 + 8) = 6; // ->state = 6 | |
v18 = pdnsGetWakeStatus(); | |
MCURTC_SetInterruptMask(&this->mcuRtcHandle, mask); | |
mcuReadWakeFlags = AcknowledgeMcuWakeEventIfEnabled(this, v18); | |
} | |
if ( v39 ) | |
ModeControlManager::SleepPxi(this, 0); // let p9 run again | |
LOBYTE(v39) = 7; | |
this->sleepState = 7; // this is the "half-awake" state | |
while ( 1 ) | |
{ | |
LODWORD(v19) = mcuReadWakeFlags & wakeupMask; | |
HIDWORD(v19) = HIDWORD(mcuReadWakeFlags) & wakeupMaskMcu; | |
v20 = GetLsb(v19); // exit | |
if ( v20 ) | |
{ | |
LODWORD(this->continueSleepReasonFlag) = 0; | |
HIDWORD(this->continueSleepReasonFlag) = 0; | |
this->wakeReasonFlags = v20; | |
goto exitSleep; | |
} | |
LODWORD(v21) = mcuReadWakeFlags & resumeSleepMask; | |
HIDWORD(v21) = HIDWORD(mcuReadWakeFlags) & resumeSleepMaskMcu; | |
v22 = GetLsb(v21); // half awake | |
this->continueSleepReasonFlag = v22; | |
if ( !v22 ) | |
break; | |
this->wakeupRequested = 0; | |
if ( *((_QWORD *)offset0x1C0_2 + 2) ) | |
PublishMcuInterrupts(this, offset0x1C0_2[5], v22, SHIDWORD(v22));// so that mcu sysmodule can handle them | |
v26 = *(void (**)(void))(offset0x180 + 0x3C);// recalculate shared time | |
if ( v26 ) | |
v26(); | |
PublishAndGetSleepSubscribers(this, 0x107u, 2u); | |
v27 = *(void (**)(void))(offset0x180 + 0x30); | |
if ( v27 ) | |
v27(); | |
v28 = this->numSubscribers; | |
v49 = this->continueSleepReasonFlag; | |
if ( v28 > 0 ) | |
{ | |
handle = &this->allSubscribersReadyEvent; | |
while ( 1 ) | |
{ | |
v29 = WaitSynchronization1(handle, 50000000LL);// 50ms | |
v39 = v29; | |
if ( v29 < 0 ) | |
DevelopmentPanic(v29); | |
v39 = v39 << 22 != 0xFF800000; | |
v30 = pdnsGetWakeStatus(); | |
v31 = AcknowledgeMcuWakeEventIfEnabled(this, v30 | mcuReadWakeFlags); | |
mcuReadWakeFlags = v31; | |
if ( v39 ) | |
break; | |
LODWORD(v31) = v31 & wakeupMask; | |
HIDWORD(v31) &= wakeupMaskMcu; | |
if ( GetLsb(v31) ) | |
break; | |
LODWORD(v32) = resumeSleepMask & mcuReadWakeFlags; | |
HIDWORD(v32) = HIDWORD(mcuReadWakeFlags) & resumeSleepMaskMcu; | |
if ( !GetLsb(v32) ) | |
{ | |
v33 = GetLsb(mcuReadWakeFlags); | |
if ( v33 ) | |
PublishMcuInterrupts(this, SHIDWORD(v33), v33, SHIDWORD(v33)); | |
} | |
if ( *((_BYTE *)v44 + 29) && !*((_BYTE *)v44 + 28) ) | |
{ | |
RecursiveLock_UnlockImpl((RecursiveLock *)&unk_110E14); | |
return; | |
} | |
} | |
} | |
if ( this->wakeupRequested ) | |
{ | |
LODWORD(this->continueSleepReasonFlag) = 0; | |
HIDWORD(this->continueSleepReasonFlag) = 0; | |
LODWORD(this->wakeReasonFlags) = 0; | |
HIDWORD(this->wakeReasonFlags) = 0; | |
goto exitSleep; | |
} | |
mcuReadWakeFlags &= ~this->continueSleepReasonFlag; | |
if ( v49 != 0x4000000 ) | |
PDNS_AcknowledgeWakeEvents(allWakeFlags); | |
} | |
v23 = GetLsb(mcuReadWakeFlags); | |
if ( v23 ) | |
PublishMcuInterrupts(this, SHIDWORD(v23), v23, SHIDWORD(v23)); | |
} | |
while ( doingSleep ); | |
exitSleep: | |
if ( *((_QWORD *)offset0x1C0_2 + 2) ) | |
PublishMcuInterrupts(this, offset0x1C0_2[5], -1, -1); | |
PDNS_SetWakeEvents(0, 0xFFFFFFFF); | |
MCURTC_ExitExclusiveInterruptMode(&this->mcuRtcHandle); | |
LOBYTE(v34) = 8; | |
this->sleepState = 8; | |
if ( *offset0x1C0_2 ) | |
((void (__cdecl *)(u32, RecursiveLock **))*offset0x1C0_2)(*offset0x1C0_2, &v34);// update rtc, no args | |
PublishAndGetSleepSubscribers(this, 0x105u, 0); | |
v25 = *(void (__cdecl **)(_DWORD, int))(offset0x180 + 0x34); | |
if ( v25 ) | |
v25(v25, v24); | |
RecursiveLock_UnlockImpl((RecursiveLock *)&unk_110E14); | |
WaitSleepPreparationCompleteAll(this); | |
svcKernelSetState(5u, 2); | |
LOBYTE(v34) = 0; | |
this->sleepState = 0; | |
PublishToSubscriber(0x106u, 0); | |
} | |
else | |
{ | |
LOBYTE(v34) = 0; | |
this->sleepState = 0; | |
PublishToSubscriber(0x102u, 0); | |
LightEvent_Signal((LightEvent *)&dword_10E300); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment