Skip to content

Instantly share code, notes, and snippets.

@TuxSH
Created May 16, 2020 16:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TuxSH/32bfd1f0952507e111939cb7acca920e to your computer and use it in GitHub Desktop.
Save TuxSH/32bfd1f0952507e111939cb7acca920e to your computer and use it in GitHub Desktop.
PTM sleep state machine
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