]> git.saurik.com Git - apple/xnu.git/blame - iokit/Families/IONetworking/IOKernelDebugger.cpp
xnu-124.13.tar.gz
[apple/xnu.git] / iokit / Families / IONetworking / IOKernelDebugger.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
24 *
25 * IOKernelDebugger.cpp
26 *
27 * HISTORY
28 */
29
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>
37
38//---------------------------------------------------------------------------
39// IOKDP
40
41#define kIOKDPEnableKDP "IOEnableKDP"
42#define kIOKDPDriverMatch "IODriverMatch"
43#define kIOKDPDriverNubMatch "IODriverNubMatch"
44
45class IOKDP : public IOService
46{
47 OSDeclareDefaultStructors( IOKDP )
48
49public:
50 static void initialize();
51
52 virtual bool start( IOService * provider );
53
54 virtual void stop( IOService * provider );
55
56 virtual bool matchProvider( IOService * provider );
57
58 virtual bool matchServiceWithDictionary( IOService * service,
59 OSDictionary * match );
60
61 virtual IOReturn message( UInt32 type,
62 IOService * provider,
63 void * argument = 0 );
64};
65
66//---------------------------------------------------------------------------
67// IOKDP defined globals.
68
69static IOLock * gIOKDPLock = 0;
70static IOKDP * gIOKDP = 0;
71
72#define super IOService
73OSDefineMetaClassAndStructorsWithInit( IOKDP, IOService,
74 IOKDP::initialize() )
75
76//---------------------------------------------------------------------------
77// Match the provider with the matching dictionary in our property table.
78
79bool IOKDP::matchProvider(IOService * provider)
80{
81 IOService * driver = 0;
82 IOService * driverNub = 0;
83 OSBoolean * aBool;
84
85 if ( provider ) driver = provider->getProvider();
86 if ( driver ) driverNub = driver->getProvider();
87
88 if ( (driver == 0) || (driverNub == 0) )
89 return false;
90
91 if ( ( aBool = OSDynamicCast(OSBoolean, getProperty(kIOKDPEnableKDP)) ) &&
92 ( aBool->isTrue() == false ) )
93 return false;
94
95 if ( matchServiceWithDictionary( driver, (OSDictionary *)
96 getProperty(kIOKDPDriverMatch)) )
97 {
98 // IOLog("IOKDP: %s\n", kIOKDPDriverMatch);
99 return true;
100 }
101
102 if ( matchServiceWithDictionary( driverNub, (OSDictionary *)
103 getProperty(kIOKDPDriverNubMatch)) )
104 {
105 // IOLog("IOKDP: %s\n", kIOKDPDriverNubMatch);
106 return true;
107 }
108
109 return false;
110}
111
112//---------------------------------------------------------------------------
113// Match an IOService with a matching dictionary.
114
115bool IOKDP::matchServiceWithDictionary(IOService * service,
116 OSDictionary * match)
117{
118 OSCollectionIterator * matchIter;
119 OSCollectionIterator * arrayIter = 0;
120 OSCollection * array;
121 OSObject * objM;
122 OSObject * objP;
123 OSSymbol * sym;
124 bool isMatch = false;
125
126 if ( ( OSDynamicCast(OSDictionary, match) == 0 ) ||
127 ( match->getCount() == 0 ) ||
128 ( (matchIter = OSCollectionIterator::withCollection(match)) == 0 ) )
129 return false;
130
131 while ( ( sym = OSDynamicCast(OSSymbol, matchIter->getNextObject()) ) )
132 {
133 objM = match->getObject(sym);
134 objP = service->getProperty(sym);
135
136 isMatch = false;
137
138 if ( arrayIter )
139 {
140 arrayIter->release();
141 arrayIter = 0;
142 }
143
144 if ( (array = OSDynamicCast( OSCollection, objM )) )
145 {
146 arrayIter = OSCollectionIterator::withCollection( array );
147 if ( arrayIter == 0 ) break;
148 }
149
150 do {
151 if ( arrayIter && ((objM = arrayIter->getNextObject()) == 0) )
152 break;
153
154 if ( objM && objP && objM->isEqualTo(objP) )
155 {
156 isMatch = true;
157 break;
158 }
159 }
160 while ( arrayIter );
161
162 if ( isMatch == false ) break;
163 }
164
165 if ( arrayIter ) arrayIter->release();
166 matchIter->release();
167
168 return isMatch;
169}
170
171//---------------------------------------------------------------------------
172// IOKDP class initializer.
173
174void IOKDP::initialize()
175{
176 gIOKDPLock = IOLockAlloc();
177 assert( gIOKDPLock );
178}
179
180//---------------------------------------------------------------------------
181// start/stop/message.
182
183bool IOKDP::start( IOService * provider )
184{
185 bool ret = false;
186
187 if ( super::start(provider) == false )
188 return false;
189
190 IOLockLock( gIOKDPLock );
191
192 do {
193 if ( gIOKDP )
194 break;
195
196 if ( matchProvider(provider) == false )
197 break;
198
199 if ( provider->open(this) == false )
200 break;
201
202 publishResource("kdp");
203
204 gIOKDP = this;
205 ret = true;
206 }
207 while ( false );
208
209 IOLockUnlock( gIOKDPLock );
210
211 return ret;
212}
213
214void IOKDP::stop( IOService * provider )
215{
216 provider->close(this);
217
218 IOLockLock( gIOKDPLock );
219
220 if ( gIOKDP == this ) gIOKDP = 0;
221
222 IOLockUnlock( gIOKDPLock );
223
224 super::stop(provider);
225}
226
227IOReturn IOKDP::message( UInt32 type,
228 IOService * provider,
229 void * argument )
230{
231 if ( type == kIOMessageServiceIsTerminated )
232 {
233 provider->close(this);
234 }
235 return kIOReturnSuccess;
236}
237
238
239//---------------------------------------------------------------------------
240// IOKernelDebugger
241
242extern "C" {
243//
244// Defined in osfmk/kdp/kdp_en_debugger.h, but the header file is not
245// exported, thus the definition is replicated here.
246//
247typedef void (*kdp_send_t)( void * pkt, UInt pkt_len );
248typedef void (*kdp_receive_t)( void * pkt, UInt * pkt_len, UInt timeout );
249void kdp_register_send_receive( kdp_send_t send, kdp_receive_t receive );
250}
251
252#undef super
253#define super IOService
254OSDefineMetaClassAndStructors( IOKernelDebugger, IOService )
255OSMetaClassDefineReservedUnused( IOKernelDebugger, 0);
256OSMetaClassDefineReservedUnused( IOKernelDebugger, 1);
257OSMetaClassDefineReservedUnused( IOKernelDebugger, 2);
258OSMetaClassDefineReservedUnused( IOKernelDebugger, 3);
259
260// IOKernelDebugger global variables.
261//
262IOService * gIODebuggerDevice = 0;
263IODebuggerTxHandler gIODebuggerTxHandler = 0;
264IODebuggerRxHandler gIODebuggerRxHandler = 0;
265UInt32 gIODebuggerTxBytes = 0;
266UInt32 gIODebuggerRxBytes = 0;
267SInt32 gIODebuggerSemaphore = 0;
268UInt32 gIODebuggerFlag = 0;
269
270// Global debugger flags.
271//
272enum {
273 kIODebuggerFlagRegistered = 0x01,
274 kIODebuggerFlagWarnNullHandler = 0x02
275};
276
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().
281
282void IOKernelDebugger::kdpReceiveDispatcher( void * buffer,
283 UInt32 * length,
284 UInt32 timeout )
285{
286 *length = 0; // return a zero length field by default.
287
288 if ( gIODebuggerSemaphore ) return; // FIXME - Driver is busy!
289
290 (*gIODebuggerRxHandler)( gIODebuggerDevice, buffer, length, timeout );
291
292 gIODebuggerRxBytes += *length;
293}
294
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().
299
300void IOKernelDebugger::kdpTransmitDispatcher( void * buffer, UInt32 length )
301{
302 if ( gIODebuggerSemaphore ) return; // FIXME - Driver is busy!
303
304 (*gIODebuggerTxHandler)( gIODebuggerDevice, buffer, length );
305
306 gIODebuggerTxBytes += length;
307}
308
309//---------------------------------------------------------------------------
310// Null debugger handlers.
311
312void IOKernelDebugger::nullTxHandler( IOService * target,
313 void * buffer,
314 UInt32 length )
315{
316}
317
318void IOKernelDebugger::nullRxHandler( IOService * target,
319 void * buffer,
320 UInt32 * length,
321 UInt32 timeout )
322{
323 if ( gIODebuggerFlag & kIODebuggerFlagWarnNullHandler )
324 {
325 IOLog("IOKernelDebugger::%s no debugger device\n", __FUNCTION__);
326 gIODebuggerFlag &= ~kIODebuggerFlagWarnNullHandler;
327 }
328}
329
330//---------------------------------------------------------------------------
331// Take the debugger lock conditionally.
332
333IODebuggerLockState IOKernelDebugger::lock( IOService * object )
334{
335 if ( gIODebuggerDevice == object )
336 {
337 OSIncrementAtomic( &gIODebuggerSemaphore );
338 return kIODebuggerLockTaken;
339 }
340 return (IODebuggerLockState) 0;
341}
342
343//---------------------------------------------------------------------------
344// Release the debugger lock if the kIODebuggerLockTaken flag is set.
345
346void IOKernelDebugger::unlock( IODebuggerLockState state )
347{
348 if ( state & kIODebuggerLockTaken )
349 OSDecrementAtomic( &gIODebuggerSemaphore );
350}
351
352//---------------------------------------------------------------------------
353// Initialize an IOKernelDebugger instance.
354
355bool IOKernelDebugger::init( IOService * target,
356 IODebuggerTxHandler txHandler,
357 IODebuggerRxHandler rxHandler )
358{
359 if ( ( super::init() == false ) ||
360 ( OSDynamicCast(IOService, target) == 0 ) ||
361 ( txHandler == 0 ) ||
362 ( rxHandler == 0 ) )
363 {
364 return false;
365 }
366
367 // Cache the target and handlers provided.
368
369 _target = target;
370 _txHandler = txHandler;
371 _rxHandler = rxHandler;
372
373 return true;
374}
375
376//---------------------------------------------------------------------------
377// Factory method which performs allocation and initialization of an
378// IOKernelDebugger instance.
379
380IOKernelDebugger * IOKernelDebugger::debugger( IOService * target,
381 IODebuggerTxHandler txHandler,
382 IODebuggerRxHandler rxHandler )
383{
384 IOKernelDebugger * debugger = new IOKernelDebugger;
385
386 if (debugger && (debugger->init( target, txHandler, rxHandler ) == false))
387 {
388 debugger->release();
389 debugger = 0;
390 }
391
392 return debugger;
393}
394
395//---------------------------------------------------------------------------
396// Register the debugger handlers.
397
398void IOKernelDebugger::registerHandler( IOService * target,
399 IODebuggerTxHandler txHandler,
400 IODebuggerRxHandler rxHandler )
401{
402 bool doRegister;
403
404 assert( ( target == gIODebuggerDevice ) ||
405 ( target == 0 ) ||
406 ( gIODebuggerDevice == 0 ) );
407
408 doRegister = ( target && ( txHandler != 0 ) && ( rxHandler != 0 ) );
409
410 if ( txHandler == 0 ) txHandler = &IOKernelDebugger::nullTxHandler;
411 if ( rxHandler == 0 ) rxHandler = &IOKernelDebugger::nullRxHandler;
412
413 OSIncrementAtomic( &gIODebuggerSemaphore );
414
415 gIODebuggerDevice = target;
416 gIODebuggerTxHandler = txHandler;
417 gIODebuggerRxHandler = rxHandler;
418 gIODebuggerFlag |= kIODebuggerFlagWarnNullHandler;
419
420 OSDecrementAtomic( &gIODebuggerSemaphore );
421
422 if ( doRegister && (( gIODebuggerFlag & kIODebuggerFlagRegistered ) == 0) )
423 {
424 // Register dispatch function, these in turn will call the
425 // handlers when the debugger is active.
426 //
427 // Note: The following call may trigger an immediate break
428 // to the debugger.
429
430 kdp_register_send_receive( (kdp_send_t) kdpTransmitDispatcher,
431 (kdp_receive_t) kdpReceiveDispatcher );
432
433 // Limit ourself to a single real KDP registration.
434
435 gIODebuggerFlag |= kIODebuggerFlagRegistered;
436 }
437}
438
439//---------------------------------------------------------------------------
440// Called by open() with the arbitration lock held.
441
442bool IOKernelDebugger::handleOpen( IOService * forClient,
443 IOOptionBits options,
444 void * arg )
445{
446 IONetworkController * ctr = OSDynamicCast(IONetworkController, _target);
447 bool ret = false;
448
449 do {
450 // Only a single client at a time.
451
452 if ( _client ) break;
453
454 // Register the target to prime the lock()/unlock() functionality
455 // before opening the target.
456
457 registerHandler( _target );
458
459 // While the target is opened/enabled, it must block any thread
460 // which may acquire the debugger lock in its execution path.
461
462 if ( _target->open( this ) == false )
463 break;
464
465 // Register interest in receiving notifications about controller
466 // power state changes.
467 //
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.
472
473 _pmDisabled = false;
474
475 if ( ctr )
476 {
477 // Register to receive PM notifications for controller power
478 // state changes.
479
480 ctr->registerInterestedDriver( this );
481
482 if ( ctr->doEnable( this ) != kIOReturnSuccess )
483 {
484 ctr->deRegisterInterestedDriver( this );
485 break;
486 }
487 }
488
489 // After the target has been opened, complete the registration.
490
491 IOLog("%s: Debugger attached\n", getName());
492 registerHandler( _target, _txHandler, _rxHandler );
493
494 // Remember the client.
495
496 _client = forClient;
497
498 ret = true;
499 }
500 while (0);
501
502 if ( ret == false )
503 {
504 registerHandler( 0 );
505 _target->close( this );
506 }
507
508 return ret;
509}
510
511//---------------------------------------------------------------------------
512// Called by IOService::close() with the arbitration lock held.
513
514void IOKernelDebugger::handleClose( IOService * forClient,
515 IOOptionBits options )
516{
517 IONetworkController * ctr = OSDynamicCast(IONetworkController, _target);
518
519 if ( _client && ( _client == forClient ) )
520 {
521 // There is no KDP un-registration. The best we can do is to
522 // register dummy handlers.
523
524 registerHandler( 0 );
525
526 if ( ctr )
527 {
528 // Disable controller if it is not already disabled.
529
530 if ( _pmDisabled == false )
531 {
532 ctr->doDisable( this );
533 }
534
535 // Before closing the controller, remove interest in receiving
536 // notifications about controller power state changes.
537
538 ctr->deRegisterInterestedDriver( this );
539 }
540
541 _client = 0;
542
543 _target->close( this );
544 }
545}
546
547//---------------------------------------------------------------------------
548// Called by IOService::isOpen() with the arbitration lock held.
549
550bool IOKernelDebugger::handleIsOpen( const IOService * forClient ) const
551{
552 if ( forClient == 0 )
553 return ( forClient != _client );
554 else
555 return ( forClient == _client );
556}
557
558//---------------------------------------------------------------------------
559// Free the IOKernelDebugger object.
560
561void IOKernelDebugger::free()
562{
563 // IOLog("IOKernelDebugger::%s %p\n", __FUNCTION__, this);
564 super::free();
565}
566
567#define PM_SECS(x) ((x) * 1000 * 1000)
568
569//---------------------------------------------------------------------------
570// Handle controller's power state change notitifications.
571
572IOReturn
573IOKernelDebugger::powerStateWillChangeTo( IOPMPowerFlags flags,
574 unsigned long stateNumber,
575 IOService * policyMaker )
576{
577 IOReturn ret = IOPMAckImplied;
578
579 if ( ( flags & IOPMDeviceUsable ) == 0 )
580 {
581 // Controller is about to transition to an un-usable state.
582 // The debugger nub should be disabled.
583
584 this->retain();
585
586 thread_call_func( (thread_call_func_t) pmDisableDebugger,
587 this, /* parameter */
588 FALSE ); /* disable unique call filter */
589
590 ret = PM_SECS(3); /* Must ACK within 3 seconds */
591 }
592
593 return ret;
594}
595
596IOReturn
597IOKernelDebugger::powerStateDidChangeTo( IOPMPowerFlags flags,
598 unsigned long stateNumber,
599 IOService * policyMaker )
600{
601 IOReturn ret = IOPMAckImplied;
602
603 if ( flags & IOPMDeviceUsable )
604 {
605 // Controller has transitioned to an usable state.
606 // The debugger nub should be enabled if necessary.
607
608 this->retain();
609
610 thread_call_func( (thread_call_func_t) pmEnableDebugger,
611 this, /* parameter */
612 FALSE ); /* disable unique call filter */
613
614 ret = PM_SECS(3); /* Must ACK within 3 seconds */
615 }
616
617 return ret;
618}
619
620//---------------------------------------------------------------------------
621// Static member function: Enable the debugger nub after the controller
622// transitions into an usable state.
623
624void IOKernelDebugger::pmEnableDebugger( IOKernelDebugger * debugger )
625{
626 IONetworkController * ctr;
627 assert( debugger );
628
629 ctr = OSDynamicCast( IONetworkController, debugger->_target );
630
631 debugger->lockForArbitration();
632
633 if ( debugger->_client && ( debugger->_pmDisabled == true ) )
634 {
635 if ( ctr && ( ctr->doEnable( debugger ) != kIOReturnSuccess ) )
636 {
637 // This is bad, unable to re-enable the controller after sleep.
638 IOLog("IOKernelDebugger: Unable to re-enable controller\n");
639 }
640 else
641 {
642 registerHandler( debugger->_target, debugger->_txHandler,
643 debugger->_rxHandler );
644
645 debugger->_pmDisabled = false;
646 }
647 }
648
649 debugger->unlockForArbitration();
650
651 // Ack the power state change.
652 debugger->_target->acknowledgePowerChange( debugger );
653
654 debugger->release();
655}
656
657//---------------------------------------------------------------------------
658// Static member function: Disable the debugger nub before the controller
659// transitions into an unusable state.
660
661void IOKernelDebugger::pmDisableDebugger( IOKernelDebugger * debugger )
662{
663 IONetworkController * ctr;
664 assert( debugger );
665
666 ctr = OSDynamicCast( IONetworkController, debugger->_target );
667
668 debugger->lockForArbitration();
669
670 if ( debugger->_client && ( debugger->_pmDisabled == false ) )
671 {
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.
675
676 registerHandler( 0 );
677 if ( ctr ) ctr->doDisable( debugger );
678
679 debugger->_pmDisabled = true;
680 }
681
682 debugger->unlockForArbitration();
683
684 // Ack the power state change.
685 debugger->_target->acknowledgePowerChange( debugger );
686
687 debugger->release();
688}