2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
25 * IOKernelDebugger.cpp
30 #include <IOKit/assert.h>
31 #include <IOKit/IOLib.h>
32 #include <IOKit/IOMessage.h>
33 #include <IOKit/IOLocks.h>
34 #include <IOKit/network/IONetworkController.h>
35 #include <IOKit/network/IOKernelDebugger.h>
36 #include <libkern/OSAtomic.h>
38 //---------------------------------------------------------------------------
41 #define kIOKDPEnableKDP "IOEnableKDP"
42 #define kIOKDPDriverMatch "IODriverMatch"
43 #define kIOKDPDriverNubMatch "IODriverNubMatch"
45 class IOKDP
: public IOService
47 OSDeclareDefaultStructors( IOKDP
)
50 static void initialize();
52 virtual bool start( IOService
* provider
);
54 virtual void stop( IOService
* provider
);
56 virtual bool matchProvider( IOService
* provider
);
58 virtual bool matchServiceWithDictionary( IOService
* service
,
59 OSDictionary
* match
);
61 virtual IOReturn
message( UInt32 type
,
63 void * argument
= 0 );
66 //---------------------------------------------------------------------------
67 // IOKDP defined globals.
69 static IOLock
* gIOKDPLock
= 0;
70 static IOKDP
* gIOKDP
= 0;
72 #define super IOService
73 OSDefineMetaClassAndStructorsWithInit( IOKDP
, IOService
,
76 //---------------------------------------------------------------------------
77 // Match the provider with the matching dictionary in our property table.
79 bool IOKDP::matchProvider(IOService
* provider
)
81 IOService
* driver
= 0;
82 IOService
* driverNub
= 0;
85 if ( provider
) driver
= provider
->getProvider();
86 if ( driver
) driverNub
= driver
->getProvider();
88 if ( (driver
== 0) || (driverNub
== 0) )
91 if ( ( aBool
= OSDynamicCast(OSBoolean
, getProperty(kIOKDPEnableKDP
)) ) &&
92 ( aBool
->isTrue() == false ) )
95 if ( matchServiceWithDictionary( driver
, (OSDictionary
*)
96 getProperty(kIOKDPDriverMatch
)) )
98 // IOLog("IOKDP: %s\n", kIOKDPDriverMatch);
102 if ( matchServiceWithDictionary( driverNub
, (OSDictionary
*)
103 getProperty(kIOKDPDriverNubMatch
)) )
105 // IOLog("IOKDP: %s\n", kIOKDPDriverNubMatch);
112 //---------------------------------------------------------------------------
113 // Match an IOService with a matching dictionary.
115 bool IOKDP::matchServiceWithDictionary(IOService
* service
,
116 OSDictionary
* match
)
118 OSCollectionIterator
* matchIter
;
119 OSCollectionIterator
* arrayIter
= 0;
120 OSCollection
* array
;
124 bool isMatch
= false;
126 if ( ( OSDynamicCast(OSDictionary
, match
) == 0 ) ||
127 ( match
->getCount() == 0 ) ||
128 ( (matchIter
= OSCollectionIterator::withCollection(match
)) == 0 ) )
131 while ( ( sym
= OSDynamicCast(OSSymbol
, matchIter
->getNextObject()) ) )
133 objM
= match
->getObject(sym
);
134 objP
= service
->getProperty(sym
);
140 arrayIter
->release();
144 if ( (array
= OSDynamicCast( OSCollection
, objM
)) )
146 arrayIter
= OSCollectionIterator::withCollection( array
);
147 if ( arrayIter
== 0 ) break;
151 if ( arrayIter
&& ((objM
= arrayIter
->getNextObject()) == 0) )
154 if ( objM
&& objP
&& objM
->isEqualTo(objP
) )
162 if ( isMatch
== false ) break;
165 if ( arrayIter
) arrayIter
->release();
166 matchIter
->release();
171 //---------------------------------------------------------------------------
172 // IOKDP class initializer.
174 void IOKDP::initialize()
176 gIOKDPLock
= IOLockAlloc();
177 assert( gIOKDPLock
);
180 //---------------------------------------------------------------------------
181 // start/stop/message.
183 bool IOKDP::start( IOService
* provider
)
187 if ( super::start(provider
) == false )
190 IOLockLock( gIOKDPLock
);
196 if ( matchProvider(provider
) == false )
199 if ( provider
->open(this) == false )
202 publishResource("kdp");
209 IOLockUnlock( gIOKDPLock
);
214 void IOKDP::stop( IOService
* provider
)
216 provider
->close(this);
218 IOLockLock( gIOKDPLock
);
220 if ( gIOKDP
== this ) gIOKDP
= 0;
222 IOLockUnlock( gIOKDPLock
);
224 super::stop(provider
);
227 IOReturn
IOKDP::message( UInt32 type
,
228 IOService
* provider
,
231 if ( type
== kIOMessageServiceIsTerminated
)
233 provider
->close(this);
235 return kIOReturnSuccess
;
239 //---------------------------------------------------------------------------
244 // Defined in osfmk/kdp/kdp_en_debugger.h, but the header file is not
245 // exported, thus the definition is replicated here.
247 typedef void (*kdp_send_t
)( void * pkt
, UInt pkt_len
);
248 typedef void (*kdp_receive_t
)( void * pkt
, UInt
* pkt_len
, UInt timeout
);
249 void kdp_register_send_receive( kdp_send_t send
, kdp_receive_t receive
);
253 #define super IOService
254 OSDefineMetaClassAndStructors( IOKernelDebugger
, IOService
)
255 OSMetaClassDefineReservedUnused( IOKernelDebugger
, 0);
256 OSMetaClassDefineReservedUnused( IOKernelDebugger
, 1);
257 OSMetaClassDefineReservedUnused( IOKernelDebugger
, 2);
258 OSMetaClassDefineReservedUnused( IOKernelDebugger
, 3);
260 // IOKernelDebugger global variables.
262 IOService
* gIODebuggerDevice
= 0;
263 IODebuggerTxHandler gIODebuggerTxHandler
= 0;
264 IODebuggerRxHandler gIODebuggerRxHandler
= 0;
265 UInt32 gIODebuggerTxBytes
= 0;
266 UInt32 gIODebuggerRxBytes
= 0;
267 SInt32 gIODebuggerSemaphore
= 0;
268 UInt32 gIODebuggerFlag
= 0;
270 // Global debugger flags.
273 kIODebuggerFlagRegistered
= 0x01,
274 kIODebuggerFlagWarnNullHandler
= 0x02
277 //---------------------------------------------------------------------------
278 // The KDP receive dispatch function. Dispatches KDP receive requests to the
279 // registered receive handler. This function is registered with KDP via
280 // kdp_register_send_receive().
282 void IOKernelDebugger::kdpReceiveDispatcher( void * buffer
,
286 *length
= 0; // return a zero length field by default.
288 if ( gIODebuggerSemaphore
) return; // FIXME - Driver is busy!
290 (*gIODebuggerRxHandler
)( gIODebuggerDevice
, buffer
, length
, timeout
);
292 gIODebuggerRxBytes
+= *length
;
295 //---------------------------------------------------------------------------
296 // The KDP transmit dispatch function. Dispatches KDP receive requests to the
297 // registered transmit handler. This function is registered with KDP via
298 // kdp_register_send_receive().
300 void IOKernelDebugger::kdpTransmitDispatcher( void * buffer
, UInt32 length
)
302 if ( gIODebuggerSemaphore
) return; // FIXME - Driver is busy!
304 (*gIODebuggerTxHandler
)( gIODebuggerDevice
, buffer
, length
);
306 gIODebuggerTxBytes
+= length
;
309 //---------------------------------------------------------------------------
310 // Null debugger handlers.
312 void IOKernelDebugger::nullTxHandler( IOService
* target
,
318 void IOKernelDebugger::nullRxHandler( IOService
* target
,
323 if ( gIODebuggerFlag
& kIODebuggerFlagWarnNullHandler
)
325 IOLog("IOKernelDebugger::%s no debugger device\n", __FUNCTION__
);
326 gIODebuggerFlag
&= ~kIODebuggerFlagWarnNullHandler
;
330 //---------------------------------------------------------------------------
331 // Take the debugger lock conditionally.
333 IODebuggerLockState
IOKernelDebugger::lock( IOService
* object
)
335 if ( gIODebuggerDevice
== object
)
337 OSIncrementAtomic( &gIODebuggerSemaphore
);
338 return kIODebuggerLockTaken
;
340 return (IODebuggerLockState
) 0;
343 //---------------------------------------------------------------------------
344 // Release the debugger lock if the kIODebuggerLockTaken flag is set.
346 void IOKernelDebugger::unlock( IODebuggerLockState state
)
348 if ( state
& kIODebuggerLockTaken
)
349 OSDecrementAtomic( &gIODebuggerSemaphore
);
352 //---------------------------------------------------------------------------
353 // Initialize an IOKernelDebugger instance.
355 bool IOKernelDebugger::init( IOService
* target
,
356 IODebuggerTxHandler txHandler
,
357 IODebuggerRxHandler rxHandler
)
359 if ( ( super::init() == false ) ||
360 ( OSDynamicCast(IOService
, target
) == 0 ) ||
361 ( txHandler
== 0 ) ||
367 // Cache the target and handlers provided.
370 _txHandler
= txHandler
;
371 _rxHandler
= rxHandler
;
376 //---------------------------------------------------------------------------
377 // Factory method which performs allocation and initialization of an
378 // IOKernelDebugger instance.
380 IOKernelDebugger
* IOKernelDebugger::debugger( IOService
* target
,
381 IODebuggerTxHandler txHandler
,
382 IODebuggerRxHandler rxHandler
)
384 IOKernelDebugger
* debugger
= new IOKernelDebugger
;
386 if (debugger
&& (debugger
->init( target
, txHandler
, rxHandler
) == false))
395 //---------------------------------------------------------------------------
396 // Register the debugger handlers.
398 void IOKernelDebugger::registerHandler( IOService
* target
,
399 IODebuggerTxHandler txHandler
,
400 IODebuggerRxHandler rxHandler
)
404 assert( ( target
== gIODebuggerDevice
) ||
406 ( gIODebuggerDevice
== 0 ) );
408 doRegister
= ( target
&& ( txHandler
!= 0 ) && ( rxHandler
!= 0 ) );
410 if ( txHandler
== 0 ) txHandler
= &IOKernelDebugger::nullTxHandler
;
411 if ( rxHandler
== 0 ) rxHandler
= &IOKernelDebugger::nullRxHandler
;
413 OSIncrementAtomic( &gIODebuggerSemaphore
);
415 gIODebuggerDevice
= target
;
416 gIODebuggerTxHandler
= txHandler
;
417 gIODebuggerRxHandler
= rxHandler
;
418 gIODebuggerFlag
|= kIODebuggerFlagWarnNullHandler
;
420 OSDecrementAtomic( &gIODebuggerSemaphore
);
422 if ( doRegister
&& (( gIODebuggerFlag
& kIODebuggerFlagRegistered
) == 0) )
424 // Register dispatch function, these in turn will call the
425 // handlers when the debugger is active.
427 // Note: The following call may trigger an immediate break
430 kdp_register_send_receive( (kdp_send_t
) kdpTransmitDispatcher
,
431 (kdp_receive_t
) kdpReceiveDispatcher
);
433 // Limit ourself to a single real KDP registration.
435 gIODebuggerFlag
|= kIODebuggerFlagRegistered
;
439 //---------------------------------------------------------------------------
440 // Called by open() with the arbitration lock held.
442 bool IOKernelDebugger::handleOpen( IOService
* forClient
,
443 IOOptionBits options
,
446 IONetworkController
* ctr
= OSDynamicCast(IONetworkController
, _target
);
450 // Only a single client at a time.
452 if ( _client
) break;
454 // Register the target to prime the lock()/unlock() functionality
455 // before opening the target.
457 registerHandler( _target
);
459 // While the target is opened/enabled, it must block any thread
460 // which may acquire the debugger lock in its execution path.
462 if ( _target
->open( this ) == false )
465 // Register interest in receiving notifications about controller
466 // power state changes.
468 // We are making an assumption that the controller is 'usable' and
469 // the next notification will inform this object that the controller
470 // has become unusable, there is no support for cases when the
471 // controller is already in an 'unusable' state.
477 // Register to receive PM notifications for controller power
480 ctr
->registerInterestedDriver( this );
482 if ( ctr
->doEnable( this ) != kIOReturnSuccess
)
484 ctr
->deRegisterInterestedDriver( this );
489 // After the target has been opened, complete the registration.
491 IOLog("%s: Debugger attached\n", getName());
492 registerHandler( _target
, _txHandler
, _rxHandler
);
494 // Remember the client.
504 registerHandler( 0 );
505 _target
->close( this );
511 //---------------------------------------------------------------------------
512 // Called by IOService::close() with the arbitration lock held.
514 void IOKernelDebugger::handleClose( IOService
* forClient
,
515 IOOptionBits options
)
517 IONetworkController
* ctr
= OSDynamicCast(IONetworkController
, _target
);
519 if ( _client
&& ( _client
== forClient
) )
521 // There is no KDP un-registration. The best we can do is to
522 // register dummy handlers.
524 registerHandler( 0 );
528 // Disable controller if it is not already disabled.
530 if ( _pmDisabled
== false )
532 ctr
->doDisable( this );
535 // Before closing the controller, remove interest in receiving
536 // notifications about controller power state changes.
538 ctr
->deRegisterInterestedDriver( this );
543 _target
->close( this );
547 //---------------------------------------------------------------------------
548 // Called by IOService::isOpen() with the arbitration lock held.
550 bool IOKernelDebugger::handleIsOpen( const IOService
* forClient
) const
552 if ( forClient
== 0 )
553 return ( forClient
!= _client
);
555 return ( forClient
== _client
);
558 //---------------------------------------------------------------------------
559 // Free the IOKernelDebugger object.
561 void IOKernelDebugger::free()
563 // IOLog("IOKernelDebugger::%s %p\n", __FUNCTION__, this);
567 #define PM_SECS(x) ((x) * 1000 * 1000)
569 //---------------------------------------------------------------------------
570 // Handle controller's power state change notitifications.
573 IOKernelDebugger::powerStateWillChangeTo( IOPMPowerFlags flags
,
574 unsigned long stateNumber
,
575 IOService
* policyMaker
)
577 IOReturn ret
= IOPMAckImplied
;
579 if ( ( flags
& IOPMDeviceUsable
) == 0 )
581 // Controller is about to transition to an un-usable state.
582 // The debugger nub should be disabled.
586 thread_call_func( (thread_call_func_t
) pmDisableDebugger
,
587 this, /* parameter */
588 FALSE
); /* disable unique call filter */
590 ret
= PM_SECS(3); /* Must ACK within 3 seconds */
597 IOKernelDebugger::powerStateDidChangeTo( IOPMPowerFlags flags
,
598 unsigned long stateNumber
,
599 IOService
* policyMaker
)
601 IOReturn ret
= IOPMAckImplied
;
603 if ( flags
& IOPMDeviceUsable
)
605 // Controller has transitioned to an usable state.
606 // The debugger nub should be enabled if necessary.
610 thread_call_func( (thread_call_func_t
) pmEnableDebugger
,
611 this, /* parameter */
612 FALSE
); /* disable unique call filter */
614 ret
= PM_SECS(3); /* Must ACK within 3 seconds */
620 //---------------------------------------------------------------------------
621 // Static member function: Enable the debugger nub after the controller
622 // transitions into an usable state.
624 void IOKernelDebugger::pmEnableDebugger( IOKernelDebugger
* debugger
)
626 IONetworkController
* ctr
;
629 ctr
= OSDynamicCast( IONetworkController
, debugger
->_target
);
631 debugger
->lockForArbitration();
633 if ( debugger
->_client
&& ( debugger
->_pmDisabled
== true ) )
635 if ( ctr
&& ( ctr
->doEnable( debugger
) != kIOReturnSuccess
) )
637 // This is bad, unable to re-enable the controller after sleep.
638 IOLog("IOKernelDebugger: Unable to re-enable controller\n");
642 registerHandler( debugger
->_target
, debugger
->_txHandler
,
643 debugger
->_rxHandler
);
645 debugger
->_pmDisabled
= false;
649 debugger
->unlockForArbitration();
651 // Ack the power state change.
652 debugger
->_target
->acknowledgePowerChange( debugger
);
657 //---------------------------------------------------------------------------
658 // Static member function: Disable the debugger nub before the controller
659 // transitions into an unusable state.
661 void IOKernelDebugger::pmDisableDebugger( IOKernelDebugger
* debugger
)
663 IONetworkController
* ctr
;
666 ctr
= OSDynamicCast( IONetworkController
, debugger
->_target
);
668 debugger
->lockForArbitration();
670 if ( debugger
->_client
&& ( debugger
->_pmDisabled
== false ) )
672 // Keep an open on the controller, but inhibit access to the
673 // controller's debugger handlers, and disable controller's
674 // hardware support for the debugger.
676 registerHandler( 0 );
677 if ( ctr
) ctr
->doDisable( debugger
);
679 debugger
->_pmDisabled
= true;
682 debugger
->unlockForArbitration();
684 // Ack the power state change.
685 debugger
->_target
->acknowledgePowerChange( debugger
);