Reputation: 556
As a security research I am writing a custom IOKit driver. The driver registers itself through the power plane to drivers it depends on. (USB services). The setPowerState
function is being called and the driver shutdown itself correctly.
Problem is, randomly it causes sleep wake failures issues and the machine restarts itself. Actually the reset occurs during a wakeup of the machine after it entered sleep (trying to hibernate apparently)
Question is, how can I debug or solve it? I am using a firewire kernel debugging to view what is going on, but the debugger and the breakpoints are causing delays in the sleep timing mechanism and everything is a mess.
Data in the internet is pretty weak regarding this issue but full of complains about OSX machines causing sleep wake failures in a clean machines.
I am testing it on various machines and kernel versions and it is persistent.
Any clue will help.
EDIT: Additional code
enum
{
kOffPowerState, kStandbyPowerState, kIdlePowertState, kOnPowerState, kNumPowerStates
};
static IOPMPowerState gPowerStates[kNumPowerStates] =
{
//kOffPowerState
{kIOPMPowerStateVersion1, 0,0,0,0,0,0,0,0,0,0,0},
//kStandbyPowerState
{kIOPMPowerStateVersion1, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0,0,0,0,0,0,0,0},
//kIdlePowerState
{kIOPMPowerStateVersion1, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0,0,0,0,0,0,0,0},
//kOnPowerState
{kIOPMPowerStateVersion1, kIOPMPowerOn | kIOPMDeviceUsable, kIOPMPowerOn, kIOPMPowerOn, 0,0,0,0,0,0,0,0}
};
bool driver::start(IOService* provider)
{
IOLog("driver::start\n");
if (IOService::start(provider) == false)
return false;
PMinit();
provider->joinPMtree(this);
makeUsable();
changePowerStateTo(0);
registerPowerDriver(this, gPowerStates, kNumPowerStates);
registerService();
return true;
}
IOReturn driver::setPowerState (unsigned long whichState, IOService * whatDevice)
{
IOLog("driver::setPowerState (%lu)\n", whichState);
if (whichState == 0)
IOLog("driver: shutdown (%lu)\n", whichState);
return kIOPMAckImplied;
}
Upvotes: 4
Views: 1686
Reputation: 556
An unreleased reference to IOService
caused a dead lock in the sleep sequence.
We used the following code to obtain IOService
pointers.
mach_timespec time;
time.tv_sec = 0;
time.tv_nsec = 1000;
IOService* service = IOService::waitForService(IOService::serviceMatching(class_name, NULL), &time);
return service;
both IOService::serviceMatching
and IOService::waitForService
increase reference counters.
Changed to the following example code:
OSDictionary *dict = IOService::serviceMatching(class_name, NULL);
if (dict == NULL)
return NULL;
IOService* service = IOService::waitForMatchingService(dict, 1000);
dict->release();
return service;
IOService::waitForMatchingService
does not increase a reference counter and we release the OSDictionary
pointer.
Upvotes: 1