]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IONetworking/IOKernelDebugger.cpp
xnu-123.5.tar.gz
[apple/xnu.git] / iokit / Families / IONetworking / IOKernelDebugger.cpp
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
45 class IOKDP : public IOService
46 {
47 OSDeclareDefaultStructors( IOKDP )
48
49 public:
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
69 static IOLock * gIOKDPLock = 0;
70 static IOKDP * gIOKDP = 0;
71
72 #define super IOService
73 OSDefineMetaClassAndStructorsWithInit( IOKDP, IOService,
74 IOKDP::initialize() )
75
76 //---------------------------------------------------------------------------
77 // Match the provider with the matching dictionary in our property table.
78
79 bool 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
115 bool 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
174 void IOKDP::initialize()
175 {
176 gIOKDPLock = IOLockAlloc();
177 assert( gIOKDPLock );
178 }
179
180 //---------------------------------------------------------------------------
181 // start/stop/message.
182
183 bool 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
214 void 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
227 IOReturn 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
242 extern "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 //
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 );
250 }
251
252 #undef super
253 #define super IOService
254 OSDefineMetaClassAndStructors( IOKernelDebugger, IOService )
255 OSMetaClassDefineReservedUnused( IOKernelDebugger, 0);
256 OSMetaClassDefineReservedUnused( IOKernelDebugger, 1);
257 OSMetaClassDefineReservedUnused( IOKernelDebugger, 2);
258 OSMetaClassDefineReservedUnused( IOKernelDebugger, 3);
259
260 // IOKernelDebugger global variables.
261 //
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;
269
270 // Global debugger flags.
271 //
272 enum {
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
282 void 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
300 void 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
312 void IOKernelDebugger::nullTxHandler( IOService * target,
313 void * buffer,
314 UInt32 length )
315 {
316 }
317
318 void 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
333 IODebuggerLockState 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
346 void IOKernelDebugger::unlock( IODebuggerLockState state )
347 {
348 if ( state & kIODebuggerLockTaken )
349 OSDecrementAtomic( &gIODebuggerSemaphore );
350 }
351
352 //---------------------------------------------------------------------------
353 // Initialize an IOKernelDebugger instance.
354
355 bool 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
380 IOKernelDebugger * 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
398 void 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
442 bool 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
514 void 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
550 bool 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
561 void 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
572 IOReturn
573 IOKernelDebugger::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
596 IOReturn
597 IOKernelDebugger::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
624 void 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
661 void 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 }