xref: /xnu-8020.101.4/iokit/Kernel/IORegistryEntry.cpp (revision e7776783b89a353188416a9a346c6cdb4928faad)
1 /*
2  * Copyright (c) 1998-2019 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <IOKit/IORegistryEntry.h>
30 #include <libkern/c++/OSContainers.h>
31 #include <IOKit/IOService.h>
32 #include <IOKit/IOKitKeys.h>
33 #include <IOKit/IOTimeStamp.h>
34 #include <libkern/c++/OSSharedPtr.h>
35 
36 #include <IOKit/IOLib.h>
37 #include <stdatomic.h>
38 #include <IOKit/assert.h>
39 #include <machine/atomic.h>
40 
41 #include "IOKitKernelInternal.h"
42 
43 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
44 
45 #define super OSObject
46 
47 OSDefineMetaClassAndStructors(IORegistryEntry, OSObject)
48 
49 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
50 
51 #define kIORegPlaneParentSuffix         "ParentLinks"
52 #define kIORegPlaneChildSuffix          "ChildLinks"
53 #define kIORegPlaneNameSuffix           "Name"
54 #define kIORegPlaneLocationSuffix       "Location"
55 
56 #define kIORegPlaneParentSuffixLen      (sizeof(kIORegPlaneParentSuffix) - 1)
57 #define kIORegPlaneChildSuffixLen       (sizeof(kIORegPlaneChildSuffix) - 1)
58 #define kIORegPlaneNameSuffixLen        (sizeof(kIORegPlaneNameSuffix) - 1)
59 #define kIORegPlaneLocationSuffixLen    (sizeof(kIORegPlaneLocationSuffix) - 1)
60 
61 #define KASLR_IOREG_DEBUG 0
62 
63 struct IORegistryEntry::ExpansionData {
64 	IORecursiveLock *        fLock;
65 	uint64_t                 fRegistryEntryID;
66 	SInt32                   fRegistryEntryGenerationCount;
67 	OSObject       **_Atomic fIndexedProperties;
68 };
69 
70 
71 static IORegistryEntry * gRegistryRoot;
72 static OSDictionary *    gIORegistryPlanes;
73 
74 const OSSymbol *        gIONameKey;
75 const OSSymbol *        gIOLocationKey;
76 const OSSymbol *        gIORegistryEntryIDKey;
77 const OSSymbol *        gIORegistryEntryPropertyKeysKey;
78 
79 enum {
80 	kParentSetIndex     = 0,
81 	kChildSetIndex      = 1,
82 	kNumSetIndex
83 };
84 enum {
85 	kIOMaxPlaneName     = 32
86 };
87 
88 enum { kIORegistryIDReserved = (1ULL << 32) + 255 };
89 
90 static uint64_t gIORegistryLastID = kIORegistryIDReserved;
91 
92 class IORegistryPlane : public OSObject {
93 	friend class IORegistryEntry;
94 
95 	OSDeclareAbstractStructors(IORegistryPlane);
96 
97 	const OSSymbol *    nameKey;
98 	const OSSymbol *    keys[kNumSetIndex];
99 	const OSSymbol *    pathNameKey;
100 	const OSSymbol *    pathLocationKey;
101 	int                 reserved[2];
102 
103 public:
104 	virtual bool serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
105 };
106 
107 OSDefineMetaClassAndStructors(IORegistryPlane, OSObject)
108 
109 
110 static IORecursiveLock *        gPropertiesLock;
111 static SInt32                   gIORegistryGenerationCount;
112 
113 #define UNLOCK  lck_rw_done( &gIORegistryLock )
114 #define RLOCK   lck_rw_lock_shared( &gIORegistryLock )
115 #define WLOCK   lck_rw_lock_exclusive( &gIORegistryLock );      \
116 	        gIORegistryGenerationCount++
117 // make atomic
118 
119 #define PUNLOCK IORecursiveLockUnlock( reserved->fLock )
120 #define PLOCK   IORecursiveLockLock( reserved->fLock )
121 
122 #define IOREGSPLITTABLES
123 
124 #ifdef IOREGSPLITTABLES
125 #define registryTable() fRegistryTable
126 #else
127 #define registryTable() fPropertyTable
128 #endif
129 
130 #define DEBUG_FREE      1
131 
132 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
133 
134 lck_rw_t        gIORegistryLock;
135 lck_grp_t       *gIORegistryLockGrp;
136 lck_grp_attr_t  *gIORegistryLockGrpAttr;
137 lck_attr_t      *gIORegistryLockAttr;
138 
139 
140 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
141 
142 IORegistryEntry *
initialize(void)143 IORegistryEntry::initialize( void )
144 {
145 	bool                 ok;
146 
147 	if (!gRegistryRoot) {
148 		gIORegistryLockGrpAttr = lck_grp_attr_alloc_init();
149 		gIORegistryLockGrp = lck_grp_alloc_init("IORegistryLock", gIORegistryLockGrpAttr);
150 		gIORegistryLockAttr = lck_attr_alloc_init();
151 		lck_attr_rw_shared_priority(gIORegistryLockAttr);
152 		lck_rw_init( &gIORegistryLock, gIORegistryLockGrp, gIORegistryLockAttr);
153 
154 		gRegistryRoot = new IORegistryEntry;
155 		gPropertiesLock = IORecursiveLockAlloc();
156 		gIORegistryPlanes = OSDictionary::withCapacity( 1 );
157 
158 		assert( gRegistryRoot && gPropertiesLock
159 		    && gIORegistryPlanes );
160 		ok = gRegistryRoot->init();
161 
162 		if (ok) {
163 			gRegistryRoot->reserved->fRegistryEntryID = ++gIORegistryLastID;
164 		}
165 
166 		gIONameKey = OSSymbol::withCStringNoCopy( "IOName" );
167 		gIOLocationKey = OSSymbol::withCStringNoCopy( "IOLocation" );
168 		gIORegistryEntryIDKey = OSSymbol::withCStringNoCopy( kIORegistryEntryIDKey );
169 		gIORegistryEntryPropertyKeysKey = OSSymbol::withCStringNoCopy( kIORegistryEntryPropertyKeysKey );
170 
171 		assert( ok && gIONameKey && gIOLocationKey );
172 
173 		gRegistryRoot->setName( "Root" );
174 		gRegistryRoot->setProperty( kIORegistryPlanesKey, gIORegistryPlanes );
175 	}
176 
177 	return gRegistryRoot;
178 }
179 
180 IORegistryEntry *
getRegistryRoot(void)181 IORegistryEntry::getRegistryRoot( void )
182 {
183 	return gRegistryRoot;
184 }
185 
186 SInt32
getGenerationCount(void)187 IORegistryEntry::getGenerationCount( void )
188 {
189 	return gIORegistryGenerationCount;
190 }
191 
192 SInt32
getRegistryEntryGenerationCount(void) const193 IORegistryEntry::getRegistryEntryGenerationCount(void) const
194 {
195 	return reserved->fRegistryEntryGenerationCount;
196 }
197 
198 const IORegistryPlane *
makePlane(const char * name)199 IORegistryEntry::makePlane( const char * name )
200 {
201 	IORegistryPlane *   plane;
202 	const OSSymbol *    nameKey;
203 	const OSSymbol *    parentKey;
204 	const OSSymbol *    childKey;
205 	const OSSymbol *    pathNameKey;
206 	const OSSymbol *    pathLocationKey;
207 	char                key[kIOMaxPlaneName + 16];
208 	char *              end;
209 
210 	strlcpy( key, name, kIOMaxPlaneName + 1 );
211 	end = key + strlen( key );
212 
213 	nameKey = OSSymbol::withCString( key);
214 
215 	strlcpy( end, kIORegPlaneParentSuffix, kIORegPlaneParentSuffixLen + 1 );
216 	parentKey = OSSymbol::withCString( key);
217 
218 	strlcpy( end, kIORegPlaneChildSuffix, kIORegPlaneChildSuffixLen + 1 );
219 	childKey = OSSymbol::withCString( key);
220 
221 	strlcpy( end, kIORegPlaneNameSuffix, kIORegPlaneNameSuffixLen + 1 );
222 	pathNameKey = OSSymbol::withCString( key);
223 
224 	strlcpy( end, kIORegPlaneLocationSuffix, kIORegPlaneLocationSuffixLen + 1 );
225 	pathLocationKey = OSSymbol::withCString( key);
226 
227 	plane = new IORegistryPlane;
228 
229 	if (plane && plane->init()
230 	    && nameKey && parentKey && childKey
231 	    && pathNameKey && pathLocationKey) {
232 		plane->nameKey = nameKey;
233 		plane->keys[kParentSetIndex] = parentKey;
234 		plane->keys[kChildSetIndex] = childKey;
235 		plane->pathNameKey = pathNameKey;
236 		plane->pathLocationKey = pathLocationKey;
237 
238 		WLOCK;
239 		gIORegistryPlanes->setObject( nameKey, plane );
240 		UNLOCK;
241 	} else {
242 		if (plane) {
243 			plane->release();
244 		}
245 		if (pathLocationKey) {
246 			pathLocationKey->release();
247 		}
248 		if (pathNameKey) {
249 			pathNameKey->release();
250 		}
251 		if (parentKey) {
252 			parentKey->release();
253 		}
254 		if (childKey) {
255 			childKey->release();
256 		}
257 		if (nameKey) {
258 			nameKey->release();
259 		}
260 		plane = NULL;
261 	}
262 
263 	return plane;
264 }
265 
266 const IORegistryPlane *
getPlane(const char * name)267 IORegistryEntry::getPlane( const char * name )
268 {
269 	const IORegistryPlane *     plane;
270 
271 	RLOCK;
272 	plane = (const IORegistryPlane *) gIORegistryPlanes->getObject( name );
273 	UNLOCK;
274 
275 	return plane;
276 }
277 
278 bool
serialize(OSSerialize * s) const279 IORegistryPlane::serialize(OSSerialize *s) const
280 {
281 	return nameKey->serialize(s);
282 }
283 
284 enum { kIORegCapacityIncrement = 4 };
285 
286 bool
init(OSDictionary * dict)287 IORegistryEntry::init( OSDictionary * dict )
288 {
289 	OSString *  prop;
290 
291 	if (!super::init()) {
292 		return false;
293 	}
294 
295 	if (!reserved) {
296 		reserved = IOMallocType(ExpansionData);
297 		reserved->fLock = IORecursiveLockAlloc();
298 		if (!reserved->fLock) {
299 			return false;
300 		}
301 	}
302 	if (dict) {
303 		if (OSCollection::kImmutable & dict->setOptions(0, 0)) {
304 			dict = (OSDictionary *) dict->copyCollection();
305 			if (!dict) {
306 				return false;
307 			}
308 		} else {
309 			dict->retain();
310 		}
311 		if (fPropertyTable) {
312 			fPropertyTable->release();
313 		}
314 		fPropertyTable = dict;
315 	} else if (!fPropertyTable) {
316 		fPropertyTable = OSDictionary::withCapacity( kIORegCapacityIncrement );
317 		if (fPropertyTable) {
318 			fPropertyTable->setCapacityIncrement( kIORegCapacityIncrement );
319 		}
320 	}
321 
322 	if (!fPropertyTable) {
323 		return false;
324 	}
325 
326 #ifdef IOREGSPLITTABLES
327 	if (!fRegistryTable) {
328 		fRegistryTable = OSDictionary::withCapacity( kIORegCapacityIncrement );
329 		if (fRegistryTable) {
330 			fRegistryTable->setCapacityIncrement( kIORegCapacityIncrement );
331 		}
332 	}
333 
334 	if ((prop = OSDynamicCast( OSString, getProperty( gIONameKey)))) {
335 		OSSymbol * sym = (OSSymbol *)OSSymbol::withString( prop);
336 		// ok for OSSymbol too
337 		setName( sym);
338 		sym->release();
339 	}
340 
341 #endif /* IOREGSPLITTABLES */
342 
343 	return true;
344 }
345 
346 bool
init(IORegistryEntry * old,const IORegistryPlane * plane)347 IORegistryEntry::init( IORegistryEntry * old,
348     const IORegistryPlane * plane )
349 {
350 	OSArray *           all;
351 	IORegistryEntry *           next;
352 	unsigned int        index;
353 
354 	if (!super::init()) {
355 		return false;
356 	}
357 
358 	if (!reserved) {
359 		reserved = IOMallocType(ExpansionData);
360 		reserved->fLock = IORecursiveLockAlloc();
361 		if (!reserved->fLock) {
362 			return false;
363 		}
364 	}
365 
366 	WLOCK;
367 
368 	reserved->fRegistryEntryID = old->reserved->fRegistryEntryID;
369 
370 	fPropertyTable = old->dictionaryWithProperties();
371 #ifdef IOREGSPLITTABLES
372 	fRegistryTable = old->fRegistryTable;
373 	old->fRegistryTable = (OSDictionary *) fRegistryTable->copyCollection();
374 #endif /* IOREGSPLITTABLES */
375 
376 	old->registryTable()->removeObject( plane->keys[kParentSetIndex] );
377 	old->registryTable()->removeObject( plane->keys[kChildSetIndex] );
378 
379 	all = getParentSetReference( plane );
380 	if (all) {
381 		for (index = 0;
382 		    (next = (IORegistryEntry *) all->getObject(index));
383 		    index++) {
384 			next->makeLink( this, kChildSetIndex, plane );
385 			next->breakLink( old, kChildSetIndex, plane );
386 		}
387 	}
388 
389 	all = getChildSetReference( plane );
390 	if (all) {
391 		for (index = 0;
392 		    (next = (IORegistryEntry *) all->getObject(index));
393 		    index++) {
394 			next->makeLink( this, kParentSetIndex, plane );
395 			next->breakLink( old, kParentSetIndex, plane );
396 		}
397 	}
398 
399 	UNLOCK;
400 
401 	return true;
402 }
403 
404 void
free(void)405 IORegistryEntry::free( void )
406 {
407 #if DEBUG_FREE
408 	if (registryTable() && gIOServicePlane) {
409 		if (getParentSetReference( gIOServicePlane )
410 		    || getChildSetReference( gIOServicePlane )) {
411 			panic("%s: attached at free()", getName());
412 		}
413 	}
414 #endif
415 
416 	if (getPropertyTable()) {
417 		getPropertyTable()->release();
418 	}
419 
420 #ifdef IOREGSPLITTABLES
421 	if (registryTable()) {
422 		registryTable()->release();
423 	}
424 #endif /* IOREGSPLITTABLES */
425 
426 	if (reserved) {
427 		OSObject ** array = os_atomic_load(&reserved->fIndexedProperties, acquire);
428 		if (array) {
429 			for (int idx = 0; idx < kIORegistryEntryIndexedPropertyCount; idx++) {
430 				if (array[idx]) {
431 					array[idx]->release();
432 				}
433 			}
434 			IODelete(array, OSObject *, kIORegistryEntryIndexedPropertyCount);
435 		}
436 		if (reserved->fLock) {
437 			IORecursiveLockFree(reserved->fLock);
438 		}
439 		IOFreeType(reserved, ExpansionData);
440 	}
441 
442 	super::free();
443 }
444 
445 void
setPropertyTable(OSDictionary * dict)446 IORegistryEntry::setPropertyTable( OSDictionary * dict )
447 {
448 	PLOCK;
449 	if (dict) {
450 		dict->retain();
451 	}
452 	if (fPropertyTable) {
453 		fPropertyTable->release();
454 	}
455 
456 	fPropertyTable = dict;
457 	PUNLOCK;
458 }
459 
460 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
461 
462 /* Wrappers to synchronize property table */
463 
464 #define wrap2(type, constant)                                           \
465 OSObject *                                                              \
466 IORegistryEntry::copyProperty( type * aKey) constant                    \
467 {                                                                       \
468     OSObject *	obj;                                                    \
469                                                                         \
470     PLOCK;                                                              \
471     obj = getProperty( aKey );                                          \
472     if( obj)                                                            \
473 	obj->retain();                                                  \
474     PUNLOCK;                                                            \
475                                                                         \
476     return( obj );                                                      \
477 }
478 
479 #define wrap4(type, constant) \
480 OSObject * \
481 IORegistryEntry::getProperty( type *                  aKey, \
482 	                      const IORegistryPlane * plane, \
483 	                      IOOptionBits            options ) constant \
484 { \
485     OSObject * obj = getProperty( aKey ); \
486     \
487     if ( (NULL == obj) && plane && (options & kIORegistryIterateRecursively) ) { \
488 	IORegistryEntry * entry = (IORegistryEntry *) this; \
489 	IORegistryIterator * iter; \
490 	iter = IORegistryIterator::iterateOver( entry, plane, options ); \
491         \
492 	if(iter) { \
493 	    while ( (NULL == obj) && (entry = iter->getNextObject()) ) { \
494 	        obj = entry->getProperty( aKey ); \
495 	    } \
496 	    iter->release(); \
497 	} \
498     } \
499     \
500     return( obj ); \
501 }
502 
503 #define wrap5(type, constant) \
504 OSObject * \
505 IORegistryEntry::copyProperty( type *                  aKey, \
506 	                      const IORegistryPlane * plane, \
507 	                      IOOptionBits            options ) constant \
508 { \
509     OSObject * obj = copyProperty( aKey ); \
510     \
511     if ( (NULL == obj) && plane && (options & kIORegistryIterateRecursively) ) { \
512 	IORegistryEntry * entry = (IORegistryEntry *) this; \
513 	IORegistryIterator * iter; \
514 	iter = IORegistryIterator::iterateOver( entry, plane, options ); \
515         \
516 	if(iter) { \
517 	    while ( (NULL == obj) && (entry = iter->getNextObject()) ) { \
518 	        obj = entry->copyProperty( aKey ); \
519 	    } \
520 	    iter->release(); \
521 	} \
522     } \
523     \
524     return( obj ); \
525 }
526 
527 bool
serializeProperties(OSSerialize * s) const528 IORegistryEntry::serializeProperties( OSSerialize * s ) const
529 {
530 //    setProperty( getRetainCount(), 32, "__retain" );
531 
532 	PLOCK;
533 	OSCollection *snapshotProperties = getPropertyTable()->copyCollection();
534 	PUNLOCK;
535 
536 	if (!snapshotProperties) {
537 		return false;
538 	}
539 
540 	bool ok =  snapshotProperties->serialize( s );
541 	snapshotProperties->release();
542 	return ok;
543 }
544 
545 OSArray *
copyPropertyKeys(void) const546 IORegistryEntry::copyPropertyKeys(void) const
547 {
548 	PLOCK;
549 	OSArray * keys = getPropertyTable()->copyKeys();
550 	PUNLOCK;
551 
552 	return keys;
553 }
554 
555 OSDictionary *
dictionaryWithProperties(void) const556 IORegistryEntry::dictionaryWithProperties( void ) const
557 {
558 	OSDictionary *      dict;
559 
560 	PLOCK;
561 	dict = OSDictionary::withDictionary( getPropertyTable(),
562 	    getPropertyTable()->getCapacity());
563 	PUNLOCK;
564 
565 	return dict;
566 }
567 
568 IOReturn
setProperties(OSObject * properties)569 IORegistryEntry::setProperties( OSObject * properties )
570 {
571 	return kIOReturnUnsupported;
572 }
573 
wrap2(const OSSymbol,const)574 wrap2(const OSSymbol, const)       // copyProperty() definition
575 wrap2(const OSString, const)       // copyProperty() definition
576 wrap2(const char, const)           // copyProperty() definition
577 
578 wrap4(const OSSymbol, const)       // getProperty() w/plane definition
579 wrap4(const OSString, const)       // getProperty() w/plane definition
580 wrap4(const char, const)           // getProperty() w/plane definition
581 
582 wrap5(const OSSymbol, const)       // copyProperty() w/plane definition
583 wrap5(const OSString, const)       // copyProperty() w/plane definition
584 wrap5(const char, const)           // copyProperty() w/plane definition
585 
586 
587 bool
588 IORegistryEntry::propertyExists(const OSSymbol * aKey)
589 {
590 	return NULL != getProperty(aKey);
591 }
592 
593 bool
propertyExists(const OSString * aKey)594 IORegistryEntry::propertyExists(const OSString * aKey)
595 {
596 	return NULL != getProperty(aKey);
597 }
598 
599 bool
propertyExists(const char * aKey)600 IORegistryEntry::propertyExists(const char * aKey)
601 {
602 	return NULL != getProperty(aKey);
603 }
604 
605 
606 bool
propertyHasValue(const OSSymbol * aKey,const OSObject * value)607 IORegistryEntry::propertyHasValue(const OSSymbol * aKey,
608     const OSObject * value)
609 {
610 	const OSObject * found;
611 	bool  result;
612 
613 	found = copyProperty(aKey);
614 	result = (!found && !value) || (found && value && value->isEqualTo(found));
615 	OSSafeReleaseNULL(found);
616 	return result;
617 }
618 
619 bool
propertyHasValue(const OSString * aKey,const OSObject * value)620 IORegistryEntry::propertyHasValue(const OSString * aKey,
621     const OSObject * value)
622 {
623 	const OSObject * found;
624 	bool  result;
625 
626 	found = copyProperty(aKey);
627 	result = (!found && !value) || (found && value && value->isEqualTo(found));
628 	OSSafeReleaseNULL(found);
629 	return result;
630 }
631 
632 bool
propertyHasValue(const char * aKey,const OSObject * value)633 IORegistryEntry::propertyHasValue(const char * aKey,
634     const OSObject * value)
635 {
636 	const OSObject * found;
637 	bool  result;
638 
639 	found = copyProperty(aKey);
640 	result = (!found && !value) || (found && value && value->isEqualTo(found));
641 	OSSafeReleaseNULL(found);
642 	return result;
643 }
644 
645 
646 bool
propertyExists(const OSSymbol * aKey,const IORegistryPlane * plane,uint32_t options) const647 IORegistryEntry::propertyExists(const OSSymbol * aKey,
648     const IORegistryPlane * plane,
649     uint32_t                options) const
650 {
651 	return NULL != getProperty(aKey, plane, options);
652 }
653 
654 bool
propertyExists(const OSString * aKey,const IORegistryPlane * plane,uint32_t options) const655 IORegistryEntry::propertyExists(const OSString * aKey,
656     const IORegistryPlane * plane,
657     uint32_t                options) const
658 {
659 	return NULL != getProperty(aKey, plane, options);
660 }
661 bool
propertyExists(const char * aKey,const IORegistryPlane * plane,uint32_t options) const662 IORegistryEntry::propertyExists(const char * aKey,
663     const IORegistryPlane * plane,
664     uint32_t                options) const
665 {
666 	return NULL != getProperty(aKey, plane, options);
667 }
668 
669 
670 bool
propertyHasValue(const OSSymbol * aKey,const OSObject * value,const IORegistryPlane * plane,uint32_t options) const671 IORegistryEntry::propertyHasValue(const OSSymbol * aKey,
672     const OSObject        * value,
673     const IORegistryPlane * plane,
674     uint32_t                options) const
675 {
676 	const OSObject * found;
677 	bool  result;
678 
679 	found = copyProperty(aKey, plane, options);
680 	result = (!found && !value) || (found && value && value->isEqualTo(found));
681 	OSSafeReleaseNULL(found);
682 	return result;
683 }
684 
685 bool
propertyHasValue(const OSString * aKey,const OSObject * value,const IORegistryPlane * plane,uint32_t options) const686 IORegistryEntry::propertyHasValue(const OSString * aKey,
687     const OSObject        * value,
688     const IORegistryPlane * plane,
689     uint32_t                options) const
690 {
691 	const OSObject * found;
692 	bool  result;
693 
694 	found = copyProperty(aKey, plane, options);
695 	result = (!found && !value) || (found && value && value->isEqualTo(found));
696 	OSSafeReleaseNULL(found);
697 	return result;
698 }
699 
700 bool
propertyHasValue(const char * aKey,const OSObject * value,const IORegistryPlane * plane,uint32_t options) const701 IORegistryEntry::propertyHasValue(const char * aKey,
702     const OSObject        * value,
703     const IORegistryPlane * plane,
704     uint32_t                options) const
705 {
706 	const OSObject * found;
707 	bool  result;
708 
709 	found = copyProperty(aKey, plane, options);
710 	result = (!found && !value) || (found && value && value->isEqualTo(found));
711 	OSSafeReleaseNULL(found);
712 	return result;
713 }
714 
715 
716 OSObject *
getProperty(const OSSymbol * aKey) const717 IORegistryEntry::getProperty( const OSSymbol * aKey) const
718 {
719 	OSObject * obj;
720 
721 	PLOCK;
722 	obj = getPropertyTable()->getObject( aKey );
723 	PUNLOCK;
724 
725 	return obj;
726 }
727 
728 void
removeProperty(const OSSymbol * aKey)729 IORegistryEntry::removeProperty( const OSSymbol * aKey)
730 {
731 	PLOCK;
732 	getPropertyTable()->removeObject( aKey );
733 	PUNLOCK;
734 }
735 
736 #if KASLR_IOREG_DEBUG
737 extern "C" {
738 bool ScanForAddrInObject(OSObject * theObject,
739     int indent);
740 }; /* extern "C" */
741 #endif
742 
743 bool
setProperty(const OSSymbol * aKey,OSObject * anObject)744 IORegistryEntry::setProperty( const OSSymbol * aKey, OSObject * anObject)
745 {
746 	bool ret = false;
747 
748 	// If we are inserting a collection class and the current entry
749 	// is attached into the registry (inPlane()) then mark the collection
750 	// as immutable.
751 	OSCollection *coll = OSDynamicCast(OSCollection, anObject);
752 	bool makeImmutable = (coll && inPlane());
753 
754 	PLOCK;
755 	if (makeImmutable) {
756 		coll->setOptions( OSCollection::kMASK, OSCollection::kImmutable );
757 	}
758 
759 	ret = getPropertyTable()->setObject( aKey, anObject );
760 	PUNLOCK;
761 
762 #if KASLR_IOREG_DEBUG
763 	if (anObject && strcmp(kIOKitDiagnosticsKey, aKey->getCStringNoCopy()) != 0) {
764 		if (ScanForAddrInObject(anObject, 0)) {
765 			IOLog("%s: IORegistryEntry name %s with key \"%s\" \n",
766 			    __FUNCTION__,
767 			    getName(0),
768 			    aKey->getCStringNoCopy());
769 		}
770 	}
771 #endif
772 
773 	return ret;
774 }
775 
776 IOReturn
777 IORegistryEntry::
runPropertyAction(Action inAction,OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)778 runPropertyAction(Action inAction, OSObject *target,
779     void *arg0, void *arg1, void *arg2, void *arg3)
780 {
781 	IOReturn res;
782 
783 	// closeGate is recursive so don't worry if we already hold the lock.
784 	PLOCK;
785 	res = (*inAction)(target, arg0, arg1, arg2, arg3);
786 	PUNLOCK;
787 
788 	return res;
789 }
790 
791 static IOReturn
IORegistryEntryActionToBlock(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)792 IORegistryEntryActionToBlock(OSObject *target,
793     void *arg0, void *arg1,
794     void *arg2, void *arg3)
795 {
796 	IORegistryEntry::ActionBlock block = (typeof(block))arg0;
797 	return block();
798 }
799 
800 IOReturn
runPropertyActionBlock(ActionBlock block)801 IORegistryEntry::runPropertyActionBlock(ActionBlock block)
802 {
803 	IOReturn res;
804 
805 	res = runPropertyAction(&IORegistryEntryActionToBlock, this, block);
806 
807 	return res;
808 }
809 
810 OSObject *
getProperty(const OSString * aKey) const811 IORegistryEntry::getProperty( const OSString * aKey) const
812 {
813 	const OSSymbol * tmpKey = OSSymbol::withString( aKey );
814 	OSObject * obj = getProperty( tmpKey );
815 
816 	tmpKey->release();
817 	return obj;
818 }
819 
820 OSObject *
getProperty(const char * aKey) const821 IORegistryEntry::getProperty( const char * aKey) const
822 {
823 	const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
824 	OSObject * obj = getProperty( tmpKey );
825 
826 	tmpKey->release();
827 	return obj;
828 }
829 
830 
831 void
removeProperty(const OSString * aKey)832 IORegistryEntry::removeProperty( const OSString * aKey)
833 {
834 	const OSSymbol * tmpKey = OSSymbol::withString( aKey );
835 	removeProperty( tmpKey );
836 	tmpKey->release();
837 }
838 
839 void
removeProperty(const char * aKey)840 IORegistryEntry::removeProperty( const char * aKey)
841 {
842 	const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
843 	removeProperty( tmpKey );
844 	tmpKey->release();
845 }
846 
847 bool
setProperty(const OSString * aKey,OSObject * anObject)848 IORegistryEntry::setProperty( const OSString * aKey, OSObject * anObject)
849 {
850 	const OSSymbol * tmpKey = OSSymbol::withString( aKey );
851 	bool ret = setProperty( tmpKey, anObject );
852 
853 	tmpKey->release();
854 	return ret;
855 }
856 
857 bool
setProperty(const char * aKey,OSObject * anObject)858 IORegistryEntry::setProperty( const char * aKey, OSObject * anObject)
859 {
860 	const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
861 	bool ret = setProperty( tmpKey, anObject );
862 
863 	tmpKey->release();
864 	return ret;
865 }
866 
867 bool
setProperty(const char * aKey,const char * aString)868 IORegistryEntry::setProperty(const char * aKey, const char * aString)
869 {
870 	bool ret = false;
871 	OSSymbol * aSymbol = (OSSymbol *) OSSymbol::withCString( aString );
872 
873 	if (aSymbol) {
874 		const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
875 		ret = setProperty( tmpKey, aSymbol );
876 
877 		tmpKey->release();
878 		aSymbol->release();
879 	}
880 	return ret;
881 }
882 
883 bool
setProperty(const char * aKey,bool aBoolean)884 IORegistryEntry::setProperty(const char * aKey, bool aBoolean)
885 {
886 	bool ret = false;
887 	OSBoolean * aBooleanObj = OSBoolean::withBoolean( aBoolean );
888 
889 	if (aBooleanObj) {
890 		const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
891 		ret = setProperty( tmpKey, aBooleanObj );
892 
893 		tmpKey->release();
894 		aBooleanObj->release();
895 	}
896 	return ret;
897 }
898 
899 bool
setProperty(const char * aKey,unsigned long long aValue,unsigned int aNumberOfBits)900 IORegistryEntry::setProperty( const char *       aKey,
901     unsigned long long aValue,
902     unsigned int       aNumberOfBits)
903 {
904 	bool ret = false;
905 	OSNumber * anOffset = OSNumber::withNumber( aValue, aNumberOfBits );
906 
907 	if (anOffset) {
908 		const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
909 		ret = setProperty( tmpKey, anOffset );
910 
911 		tmpKey->release();
912 		anOffset->release();
913 	}
914 	return ret;
915 }
916 
917 bool
setProperty(const char * aKey,void * bytes,unsigned int length)918 IORegistryEntry::setProperty( const char *      aKey,
919     void *            bytes,
920     unsigned int      length)
921 {
922 	bool ret = false;
923 	OSData * data = OSData::withBytes( bytes, length );
924 
925 	if (data) {
926 		const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
927 		ret = setProperty( tmpKey, data );
928 
929 		tmpKey->release();
930 		data->release();
931 	}
932 	return ret;
933 }
934 
935 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
936 
937 OSObject *
setIndexedProperty(uint32_t index,OSObject * anObject)938 IORegistryEntry::setIndexedProperty(uint32_t index, OSObject * anObject)
939 {
940 	OSObject ** array;
941 	OSObject *  prior;
942 
943 	if (index >= kIORegistryEntryIndexedPropertyCount) {
944 		return NULL;
945 	}
946 
947 	array = os_atomic_load(&reserved->fIndexedProperties, acquire);
948 	if (!array) {
949 		array = IONew(OSObject *, kIORegistryEntryIndexedPropertyCount);
950 		if (!array) {
951 			return NULL;
952 		}
953 		bzero(array, kIORegistryEntryIndexedPropertyCount * sizeof(array[0]));
954 		if (!os_atomic_cmpxchg(&reserved->fIndexedProperties, NULL, array, release)) {
955 			IODelete(array, OSObject *, kIORegistryEntryIndexedPropertyCount);
956 			array = os_atomic_load(&reserved->fIndexedProperties, acquire);
957 		}
958 	}
959 
960 	if (!array) {
961 		return NULL;
962 	}
963 
964 	prior = array[index];
965 	if (anObject) {
966 		anObject->retain();
967 	}
968 	array[index] = anObject;
969 
970 	return prior;
971 }
972 
973 OSObject *
getIndexedProperty(uint32_t index) const974 IORegistryEntry::getIndexedProperty(uint32_t index) const
975 {
976 	if (index >= kIORegistryEntryIndexedPropertyCount) {
977 		return NULL;
978 	}
979 
980 	OSObject ** array = os_atomic_load(&reserved->fIndexedProperties, acquire);
981 	if (!array) {
982 		return NULL;
983 	}
984 
985 	return array[index];
986 }
987 
988 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
989 
990 /* Name, location, paths */
991 
992 const char *
getName(const IORegistryPlane * plane) const993 IORegistryEntry::getName( const IORegistryPlane * plane ) const
994 {
995 	OSSymbol *          sym = NULL;
996 
997 	RLOCK;
998 	if (plane) {
999 		sym = (OSSymbol *) registryTable()->getObject( plane->pathNameKey );
1000 	}
1001 	if (!sym) {
1002 		sym = (OSSymbol *) registryTable()->getObject( gIONameKey );
1003 	}
1004 	UNLOCK;
1005 
1006 	if (sym) {
1007 		return sym->getCStringNoCopy();
1008 	} else {
1009 		return (getMetaClass())->getClassName();
1010 	}
1011 }
1012 
1013 const OSSymbol *
copyName(const IORegistryPlane * plane) const1014 IORegistryEntry::copyName(
1015 	const IORegistryPlane * plane ) const
1016 {
1017 	OSSymbol *          sym = NULL;
1018 
1019 	RLOCK;
1020 	if (plane) {
1021 		sym = (OSSymbol *) registryTable()->getObject( plane->pathNameKey );
1022 	}
1023 	if (!sym) {
1024 		sym = (OSSymbol *) registryTable()->getObject( gIONameKey );
1025 	}
1026 	if (sym) {
1027 		sym->retain();
1028 	}
1029 	UNLOCK;
1030 
1031 	if (sym) {
1032 		return sym;
1033 	} else {
1034 		return OSSymbol::withCString((getMetaClass())->getClassName());
1035 	}
1036 }
1037 
1038 const OSSymbol *
copyLocation(const IORegistryPlane * plane) const1039 IORegistryEntry::copyLocation(
1040 	const IORegistryPlane * plane ) const
1041 {
1042 	OSSymbol *          sym = NULL;
1043 
1044 	RLOCK;
1045 	if (plane) {
1046 		sym = (OSSymbol *) registryTable()->getObject( plane->pathLocationKey );
1047 	}
1048 	if (!sym) {
1049 		sym = (OSSymbol *) registryTable()->getObject( gIOLocationKey );
1050 	}
1051 	if (sym) {
1052 		sym->retain();
1053 	}
1054 	UNLOCK;
1055 
1056 	return sym;
1057 }
1058 
1059 const char *
getLocation(const IORegistryPlane * plane) const1060 IORegistryEntry::getLocation( const IORegistryPlane * plane ) const
1061 {
1062 	const OSSymbol *    sym = copyLocation( plane );
1063 	const char *        result = NULL;
1064 
1065 	if (sym) {
1066 		result = sym->getCStringNoCopy();
1067 		sym->release();
1068 	}
1069 
1070 	return result;
1071 }
1072 
1073 void
setName(const OSSymbol * name,const IORegistryPlane * plane)1074 IORegistryEntry::setName( const OSSymbol * name,
1075     const IORegistryPlane * plane )
1076 {
1077 	const OSSymbol *    key;
1078 
1079 	if (name) {
1080 		if (plane) {
1081 			key = plane->pathNameKey;
1082 		} else {
1083 			key = gIONameKey;
1084 		}
1085 
1086 		if (gIOKitTrace && reserved && reserved->fRegistryEntryID) {
1087 			uint64_t str_id = 0;
1088 			uint64_t __unused regID = getRegistryEntryID();
1089 			kernel_debug_string(IODBG_IOREGISTRY(IOREGISTRYENTRY_NAME_STRING), &str_id, name->getCStringNoCopy());
1090 			KERNEL_DEBUG_CONSTANT(IODBG_IOREGISTRY(IOREGISTRYENTRY_NAME),
1091 			    (uintptr_t) regID,
1092 			    (uintptr_t) (regID >> 32),
1093 			    (uintptr_t) str_id,
1094 			    (uintptr_t) (str_id >> 32),
1095 			    0);
1096 		}
1097 
1098 		WLOCK;
1099 		OS_ANALYZER_SUPPRESS("82033761") registryTable()->setObject( key, (OSObject *) name);
1100 		UNLOCK;
1101 	}
1102 }
1103 
1104 void
setName(const char * name,const IORegistryPlane * plane)1105 IORegistryEntry::setName( const char * name,
1106     const IORegistryPlane * plane )
1107 {
1108 	OSSymbol * sym = (OSSymbol *)OSSymbol::withCString( name );
1109 	if (sym) {
1110 		setName( sym, plane );
1111 		sym->release();
1112 	}
1113 }
1114 
1115 void
setName(const OSString * name,const IORegistryPlane * plane)1116 IORegistryEntry::setName( const OSString * name,
1117     const IORegistryPlane * plane )
1118 {
1119 	const OSSymbol * sym = OSSymbol::withString( name );
1120 	if (sym) {
1121 		setName( sym, plane );
1122 		sym->release();
1123 	}
1124 }
1125 
1126 void
setLocation(const OSSymbol * location,const IORegistryPlane * plane)1127 IORegistryEntry::setLocation( const OSSymbol * location,
1128     const IORegistryPlane * plane )
1129 {
1130 	const OSSymbol *    key;
1131 
1132 	if (location) {
1133 		if (plane) {
1134 			key = plane->pathLocationKey;
1135 		} else {
1136 			key = gIOLocationKey;
1137 		}
1138 
1139 		WLOCK;
1140 		registryTable()->setObject( key, (OSObject *) location);
1141 		UNLOCK;
1142 	}
1143 }
1144 
1145 void
setLocation(const char * location,const IORegistryPlane * plane)1146 IORegistryEntry::setLocation( const char * location,
1147     const IORegistryPlane * plane )
1148 {
1149 	OSSymbol * sym = (OSSymbol *)OSSymbol::withCString( location );
1150 	if (sym) {
1151 		setLocation( sym, plane );
1152 		sym->release();
1153 	}
1154 }
1155 
1156 
1157 bool
compareName(OSString * name,OSString ** matched) const1158 IORegistryEntry::compareName( OSString * name, OSString ** matched ) const
1159 {
1160 	const OSSymbol *    sym = copyName();
1161 	bool                isEqual;
1162 
1163 	isEqual = (sym && sym->isEqualTo(name));
1164 
1165 	if (isEqual && matched) {
1166 		name->retain();
1167 		*matched = name;
1168 	}
1169 
1170 	if (sym) {
1171 		sym->release();
1172 	}
1173 
1174 	return isEqual;
1175 }
1176 
1177 bool
compareNames(OSObject * names,OSString ** matched) const1178 IORegistryEntry::compareNames( OSObject * names, OSString ** matched ) const
1179 {
1180 	OSString *          string;
1181 	OSCollection *      collection;
1182 	OSIterator *        iter = NULL;
1183 	bool                result = false;
1184 
1185 	if ((collection = OSDynamicCast( OSCollection, names))) {
1186 		iter = OSCollectionIterator::withCollection( collection );
1187 		string = NULL;
1188 	} else {
1189 		string = OSDynamicCast( OSString, names);
1190 	}
1191 
1192 	do {
1193 		if (string) {
1194 			result = compareName( string, matched );
1195 		}
1196 	} while ((false == result)
1197 	    && iter && (string = OSDynamicCast( OSString, iter->getNextObject())));
1198 
1199 	if (iter) {
1200 		iter->release();
1201 	}
1202 
1203 	return result;
1204 }
1205 
1206 bool
compareName(OSString * name,OSSharedPtr<OSString> & matched) const1207 IORegistryEntry::compareName( OSString * name, OSSharedPtr<OSString>& matched ) const
1208 {
1209 	OSString* matchedRaw = NULL;
1210 	bool result = compareName(name, &matchedRaw);
1211 	matched.reset(matchedRaw, OSNoRetain);
1212 	return result;
1213 }
1214 
1215 bool
compareNames(OSObject * names,OSSharedPtr<OSString> & matched) const1216 IORegistryEntry::compareNames( OSObject * names, OSSharedPtr<OSString>& matched ) const
1217 {
1218 	OSString* matchedRaw = NULL;
1219 	bool result = compareNames(names, &matchedRaw);
1220 	matched.reset(matchedRaw, OSNoRetain);
1221 	return result;
1222 }
1223 
1224 bool
getPath(char * path,int * length,const IORegistryPlane * plane) const1225 IORegistryEntry::getPath(  char * path, int * length,
1226     const IORegistryPlane * plane ) const
1227 {
1228 	OSArray *           stack;
1229 	IORegistryEntry *   root;
1230 	const IORegistryEntry * entry;
1231 	const IORegistryEntry * parent;
1232 	const OSSymbol *    alias;
1233 	int                 index;
1234 	int                 len, maxLength, compLen, aliasLen;
1235 	char *              nextComp;
1236 	bool                ok;
1237 
1238 	if (!path || !length || !plane) {
1239 		return false;
1240 	}
1241 
1242 	len = 0;
1243 	maxLength = *length - 2;
1244 	nextComp = path;
1245 
1246 	len = plane->nameKey->getLength();
1247 	if (len >= maxLength) {
1248 		return false;
1249 	}
1250 	strlcpy( nextComp, plane->nameKey->getCStringNoCopy(), len + 1);
1251 	nextComp[len++] = ':';
1252 	nextComp += len;
1253 
1254 	if ((alias = hasAlias( plane ))) {
1255 		aliasLen = alias->getLength();
1256 		len += aliasLen;
1257 		ok = (maxLength > len);
1258 		*length = len;
1259 		if (ok) {
1260 			strlcpy( nextComp, alias->getCStringNoCopy(), aliasLen + 1);
1261 		}
1262 		return ok;
1263 	}
1264 
1265 	stack = OSArray::withCapacity( getDepth( plane ));
1266 	if (!stack) {
1267 		return false;
1268 	}
1269 
1270 	RLOCK;
1271 
1272 	parent = entry = this;
1273 	root = gRegistryRoot->getChildEntry( plane );
1274 	while (parent && (parent != root)) {
1275 		// stop below root
1276 		entry = parent;
1277 		parent = entry->getParentEntry( plane );
1278 		stack->setObject((OSObject *) entry );
1279 	}
1280 
1281 	ok = (NULL != parent);
1282 	if (ok) {
1283 		index = stack->getCount();
1284 		if (0 == index) {
1285 			*nextComp++ = '/';
1286 			*nextComp = 0;
1287 			len++;
1288 		} else {
1289 			while (ok && ((--index) >= 0)) {
1290 				entry = (IORegistryEntry *) stack->getObject((unsigned int) index );
1291 				assert( entry );
1292 
1293 				if ((alias = entry->hasAlias( plane ))) {
1294 					len = plane->nameKey->getLength() + 1;
1295 					nextComp = path + len;
1296 
1297 					compLen = alias->getLength();
1298 					ok = (maxLength > (len + compLen));
1299 					if (ok) {
1300 						strlcpy( nextComp, alias->getCStringNoCopy(), compLen + 1);
1301 					}
1302 				} else {
1303 					compLen = maxLength - len;
1304 					ok = entry->getPathComponent( nextComp + 1, &compLen, plane );
1305 
1306 					if (ok && compLen) {
1307 						compLen++;
1308 						*nextComp = '/';
1309 					}
1310 				}
1311 
1312 				if (ok) {
1313 					len += compLen;
1314 					nextComp += compLen;
1315 				}
1316 			}
1317 		}
1318 		*length = len;
1319 	}
1320 	UNLOCK;
1321 	stack->release();
1322 
1323 	return ok;
1324 }
1325 
1326 bool
getPathComponent(char * path,int * length,const IORegistryPlane * plane) const1327 IORegistryEntry::getPathComponent( char * path, int * length,
1328     const IORegistryPlane * plane ) const
1329 {
1330 	int                 len, locLen, maxLength;
1331 	const char *        compName;
1332 	const char *        loc;
1333 	bool                ok;
1334 
1335 	maxLength = *length;
1336 
1337 	compName = getName( plane );
1338 	len = (int) strnlen( compName, sizeof(io_name_t));
1339 	if ((loc = getLocation( plane ))) {
1340 		locLen = 1 + ((int) strnlen( loc, sizeof(io_name_t)));
1341 	} else {
1342 		locLen = 0;
1343 	}
1344 
1345 	ok = ((len + locLen + 1) < maxLength);
1346 	if (ok) {
1347 		strlcpy( path, compName, len + 1 );
1348 		if (loc) {
1349 			path += len;
1350 			len += locLen;
1351 			*path++ = '@';
1352 			strlcpy( path, loc, locLen );
1353 		}
1354 		*length = len;
1355 	}
1356 
1357 	return ok;
1358 }
1359 
1360 const char *
matchPathLocation(const char * cmp,const IORegistryPlane * plane)1361 IORegistryEntry::matchPathLocation( const char * cmp,
1362     const IORegistryPlane * plane )
1363 {
1364 	const char  *       str;
1365 	const char  *       result = NULL;
1366 	u_quad_t            num1, num2;
1367 	char                lastPathChar, lastLocationChar;
1368 
1369 	str = getLocation( plane );
1370 	if (str) {
1371 		lastPathChar = cmp[0];
1372 		lastLocationChar = str[0];
1373 		do {
1374 			if (lastPathChar) {
1375 				num1 = strtouq( cmp, (char **) &cmp, 16 );
1376 				lastPathChar = *cmp++;
1377 			} else {
1378 				num1 = 0;
1379 			}
1380 
1381 			if (lastLocationChar) {
1382 				num2 = strtouq( str, (char **) &str, 16 );
1383 				lastLocationChar = *str++;
1384 			} else {
1385 				num2 = 0;
1386 			}
1387 
1388 			if (num1 != num2) {
1389 				break;
1390 			}
1391 
1392 			if (!lastPathChar && !lastLocationChar) {
1393 				result = cmp - 1;
1394 				break;
1395 			}
1396 
1397 			if ((',' != lastPathChar) && (':' != lastPathChar)) {
1398 				lastPathChar = 0;
1399 			}
1400 
1401 			if (lastPathChar && lastLocationChar && (lastPathChar != lastLocationChar)) {
1402 				break;
1403 			}
1404 		} while (true);
1405 	}
1406 
1407 	return result;
1408 }
1409 
1410 IORegistryEntry *
getChildFromComponent(const char ** opath,const IORegistryPlane * plane)1411 IORegistryEntry::getChildFromComponent( const char ** opath,
1412     const IORegistryPlane * plane )
1413 {
1414 	IORegistryEntry *   entry = NULL;
1415 	OSArray *           set;
1416 	unsigned int        index;
1417 	const char *        path;
1418 	const char *        cmp = NULL;
1419 	char                c;
1420 	size_t              len;
1421 	const char *        str;
1422 
1423 	set = getChildSetReference( plane );
1424 	if (set) {
1425 		path = *opath;
1426 
1427 		for (index = 0;
1428 		    (entry = (IORegistryEntry *) set->getObject(index));
1429 		    index++) {
1430 			cmp = path;
1431 
1432 			if (*cmp != '@') {
1433 				str = entry->getName( plane );
1434 				len = strlen( str );
1435 				if (strncmp( str, cmp, len )) {
1436 					continue;
1437 				}
1438 				cmp += len;
1439 
1440 				c = *cmp;
1441 				if ((c == 0) || (c == '/') || (c == ':')) {
1442 					break;
1443 				}
1444 				if (c != '@') {
1445 					continue;
1446 				}
1447 			}
1448 			cmp++;
1449 			if ((cmp = entry->matchPathLocation( cmp, plane ))) {
1450 				break;
1451 			}
1452 		}
1453 		if (entry) {
1454 			*opath = cmp;
1455 		}
1456 	}
1457 
1458 	return entry;
1459 }
1460 
1461 const OSSymbol *
hasAlias(const IORegistryPlane * plane,char * opath,int * length) const1462 IORegistryEntry::hasAlias( const IORegistryPlane * plane,
1463     char * opath, int * length ) const
1464 {
1465 	IORegistryEntry *   entry;
1466 	IORegistryEntry *   entry2;
1467 	const OSSymbol *    key;
1468 	const OSSymbol *    bestKey = NULL;
1469 	OSIterator *        iter;
1470 	OSData *            data;
1471 	const char *        path = "/aliases";
1472 
1473 	entry = IORegistryEntry::fromPath( path, plane );
1474 	if (entry) {
1475 		RLOCK;
1476 		if ((iter = OSCollectionIterator::withCollection(
1477 			    entry->getPropertyTable()))) {
1478 			while ((key = (OSSymbol *) iter->getNextObject())) {
1479 				data = (OSData *) entry->getProperty( key );
1480 				path = (const char *) data->getBytesNoCopy();
1481 				if ((entry2 = IORegistryEntry::fromPath( path, plane,
1482 				    opath, length ))) {
1483 					if (this == entry2) {
1484 						if (!bestKey
1485 						    || (bestKey->getLength() > key->getLength())) {
1486 							// pick the smallest alias
1487 							bestKey = key;
1488 						}
1489 					}
1490 					entry2->release();
1491 				}
1492 			}
1493 			iter->release();
1494 		}
1495 		entry->release();
1496 		UNLOCK;
1497 	}
1498 	return bestKey;
1499 }
1500 
1501 const char *
dealiasPath(const char ** opath,const IORegistryPlane * plane)1502 IORegistryEntry::dealiasPath(
1503 	const char **           opath,
1504 	const IORegistryPlane * plane )
1505 {
1506 	IORegistryEntry *   entry;
1507 	OSData *            data;
1508 	const char *        path = *opath;
1509 	const char *        rpath = NULL;
1510 	const char *        end;
1511 	char                c;
1512 	char                temp[kIOMaxPlaneName + 1];
1513 
1514 	if (path[0] == '/') {
1515 		return rpath;
1516 	}
1517 
1518 	// check for alias
1519 	end = path;
1520 	while ((c = *end++) && (c != '/') && (c != ':')) {
1521 	}
1522 	end--;
1523 	if ((end - path) < kIOMaxPlaneName) {
1524 		strlcpy( temp, path, end - path + 1 );
1525 
1526 		RLOCK;
1527 		entry = IORegistryEntry::fromPath( "/aliases", plane );
1528 		if (entry) {
1529 			data = (OSData *) entry->getProperty( temp );
1530 			if (data) {
1531 				rpath = (const char *) data->getBytesNoCopy();
1532 				if (rpath) {
1533 					*opath = end;
1534 				}
1535 			}
1536 			entry->release();
1537 		}
1538 		UNLOCK;
1539 	}
1540 
1541 	return rpath;
1542 }
1543 
1544 IORegistryEntry *
fromPath(const char * path,const IORegistryPlane * plane,char * opath,int * length,IORegistryEntry * fromEntry)1545 IORegistryEntry::fromPath(
1546 	const char *            path,
1547 	const IORegistryPlane * plane,
1548 	char *                  opath,
1549 	int *                   length,
1550 	IORegistryEntry *       fromEntry )
1551 {
1552 	IORegistryEntry *   where = NULL;
1553 	IORegistryEntry *   aliasEntry = NULL;
1554 	IORegistryEntry *   next;
1555 	const char *        alias;
1556 	const char *        end;
1557 	int                 len = 0;
1558 	int                 len2;
1559 	char                c;
1560 	char                temp[kIOMaxPlaneName + 1];
1561 
1562 	if (NULL == path) {
1563 		return NULL;
1564 	}
1565 
1566 	if (NULL == plane) {
1567 		// get plane name
1568 		end = strchr( path, ':' );
1569 		if (end && ((end - path) < kIOMaxPlaneName)) {
1570 			strlcpy( temp, path, end - path + 1 );
1571 			plane = getPlane( temp );
1572 			path = end + 1;
1573 		}
1574 	}
1575 	if (NULL == plane) {
1576 		return NULL;
1577 	}
1578 
1579 	// check for alias
1580 	end = path;
1581 	if ((alias = dealiasPath( &end, plane))) {
1582 		if (length) {
1583 			len = *length;
1584 		}
1585 		aliasEntry = IORegistryEntry::fromPath( alias, plane,
1586 		    opath, &len, fromEntry );
1587 		where = aliasEntry;
1588 		if (where) {
1589 			path = end;
1590 		} else {
1591 			len = 0;
1592 		}
1593 	}
1594 
1595 	RLOCK;
1596 
1597 	do {
1598 		if (NULL == where) {
1599 			if ((NULL == fromEntry) && (*path++ == '/')) {
1600 				fromEntry = gRegistryRoot->getChildEntry( plane );
1601 			}
1602 			where = fromEntry;
1603 			if (NULL == where) {
1604 				break;
1605 			}
1606 		} else {
1607 			c = *path++;
1608 			if (c != '/') {
1609 				if (c && (c != ':')) { // check valid terminator
1610 					where = NULL;
1611 				}
1612 				break;
1613 			}
1614 		}
1615 		next = where->getChildFromComponent( &path, plane );
1616 		if (next) {
1617 			where = next;
1618 		}
1619 	} while (next);
1620 
1621 	if (where) {
1622 		// check residual path
1623 		if (where != fromEntry) {
1624 			path--;
1625 		}
1626 
1627 		if (opath && length) {
1628 			// copy out residual path
1629 			len2 = (int) strnlen(path, 65536);
1630 			if ((len + len2) < *length) {
1631 				strlcpy( opath + len, path, len2 + 1 );
1632 			}
1633 			*length = (len + len2);
1634 		} else if (path[0]) {
1635 			// no residual path => must be no tail for success
1636 			where = NULL;
1637 		}
1638 	}
1639 
1640 	if (where) {
1641 		where->retain();
1642 	}
1643 	if (aliasEntry) {
1644 		aliasEntry->release();
1645 	}
1646 
1647 	UNLOCK;
1648 
1649 	return where;
1650 }
1651 
1652 IORegistryEntry *
childFromPath(const char * path,const IORegistryPlane * plane,char * opath,int * len)1653 IORegistryEntry::childFromPath(
1654 	const char *            path,
1655 	const IORegistryPlane * plane,
1656 	char *                  opath,
1657 	int *                   len )
1658 {
1659 	return IORegistryEntry::fromPath( path, plane, opath, len, this );
1660 }
1661 
1662 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1663 
1664 #define IOLinkIterator OSCollectionIterator
1665 
1666 #undef super
1667 #define super OSObject
1668 
1669 inline bool
arrayMember(OSArray * set,const IORegistryEntry * member,unsigned int * index) const1670 IORegistryEntry::arrayMember( OSArray * set,
1671     const IORegistryEntry * member,
1672     unsigned int * index ) const
1673 {
1674 	int         i;
1675 	OSObject *  probeObject;
1676 
1677 	for (i = 0; (probeObject = set->getObject(i)); i++) {
1678 		if (probeObject == (OSObject *) member) {
1679 			if (index) {
1680 				*index = i;
1681 			}
1682 			return true;
1683 		}
1684 	}
1685 	return false;
1686 }
1687 
1688 bool
makeLink(IORegistryEntry * to,unsigned int relation,const IORegistryPlane * plane) const1689 IORegistryEntry::makeLink( IORegistryEntry * to,
1690     unsigned int relation,
1691     const IORegistryPlane * plane ) const
1692 {
1693 	OSArray *   links;
1694 	bool        result = false;
1695 
1696 	if ((links = (OSArray *)
1697 	    registryTable()->getObject( plane->keys[relation] ))) {
1698 		result = arrayMember( links, to );
1699 		if (!result) {
1700 			result = links->setObject( to );
1701 		}
1702 	} else {
1703 		links = OSArray::withObjects((const OSObject **) &to, 1, 1 );
1704 		result = (links != NULL);
1705 		if (result) {
1706 			result = registryTable()->setObject( plane->keys[relation],
1707 			    links );
1708 			links->release();
1709 		}
1710 	}
1711 	reserved->fRegistryEntryGenerationCount++;
1712 
1713 	return result;
1714 }
1715 
1716 void
breakLink(IORegistryEntry * to,unsigned int relation,const IORegistryPlane * plane) const1717 IORegistryEntry::breakLink( IORegistryEntry * to,
1718     unsigned int relation,
1719     const IORegistryPlane * plane ) const
1720 {
1721 	OSArray *           links;
1722 	unsigned int        index;
1723 
1724 	if ((links = (OSArray *)
1725 	    registryTable()->getObject( plane->keys[relation]))) {
1726 		if (arrayMember( links, to, &index )) {
1727 			links->removeObject( index );
1728 			if (0 == links->getCount()) {
1729 				registryTable()->removeObject( plane->keys[relation]);
1730 			}
1731 		}
1732 	}
1733 	reserved->fRegistryEntryGenerationCount++;
1734 }
1735 
1736 
1737 OSArray *
getParentSetReference(const IORegistryPlane * plane) const1738 IORegistryEntry::getParentSetReference(
1739 	const IORegistryPlane * plane ) const
1740 {
1741 	if (plane) {
1742 		return (OSArray *) registryTable()->getObject(
1743 			plane->keys[kParentSetIndex]);
1744 	} else {
1745 		return NULL;
1746 	}
1747 }
1748 
1749 OSIterator *
getParentIterator(const IORegistryPlane * plane) const1750 IORegistryEntry::getParentIterator(
1751 	const IORegistryPlane * plane ) const
1752 {
1753 	OSArray *           links;
1754 	OSIterator *        iter;
1755 
1756 	if (!plane) {
1757 		return NULL;
1758 	}
1759 
1760 	RLOCK;
1761 	links = getParentSetReference( plane );
1762 	if (NULL == links) {
1763 		links = OSArray::withCapacity( 1 );
1764 	} else {
1765 		links = OSArray::withArray( links, links->getCount());
1766 	}
1767 	UNLOCK;
1768 
1769 	iter = IOLinkIterator::withCollection( links );
1770 
1771 	if (links) {
1772 		links->release();
1773 	}
1774 
1775 	return iter;
1776 }
1777 
1778 IORegistryEntry *
copyParentEntry(const IORegistryPlane * plane) const1779 IORegistryEntry::copyParentEntry( const IORegistryPlane * plane ) const
1780 {
1781 	IORegistryEntry *   entry = NULL;
1782 	OSArray *           links;
1783 
1784 	RLOCK;
1785 
1786 	if ((links = getParentSetReference( plane ))) {
1787 		entry = (IORegistryEntry *) links->getObject( 0 );
1788 		entry->retain();
1789 	}
1790 
1791 	UNLOCK;
1792 
1793 	return entry;
1794 }
1795 
1796 IORegistryEntry *
getParentEntry(const IORegistryPlane * plane) const1797 IORegistryEntry::getParentEntry( const IORegistryPlane * plane ) const
1798 {
1799 	IORegistryEntry * entry;
1800 
1801 	entry = copyParentEntry( plane );
1802 	if (entry) {
1803 		entry->release();
1804 	}
1805 
1806 	return entry;
1807 }
1808 
1809 OSArray *
getChildSetReference(const IORegistryPlane * plane) const1810 IORegistryEntry::getChildSetReference( const IORegistryPlane * plane ) const
1811 {
1812 	if (plane) {
1813 		return (OSArray *) registryTable()->getObject(
1814 			plane->keys[kChildSetIndex]);
1815 	} else {
1816 		return NULL;
1817 	}
1818 }
1819 
1820 OSIterator *
getChildIterator(const IORegistryPlane * plane) const1821 IORegistryEntry::getChildIterator( const IORegistryPlane * plane ) const
1822 {
1823 	OSArray *           links;
1824 	OSIterator *        iter;
1825 
1826 	if (!plane) {
1827 		return NULL;
1828 	}
1829 
1830 	RLOCK;
1831 	links = getChildSetReference( plane );
1832 	if (NULL == links) {
1833 		links = OSArray::withCapacity( 1 );
1834 	} else {
1835 		links = OSArray::withArray( links, links->getCount());
1836 	}
1837 	UNLOCK;
1838 
1839 	iter = IOLinkIterator::withCollection( links );
1840 
1841 	if (links) {
1842 		links->release();
1843 	}
1844 
1845 	return iter;
1846 }
1847 
1848 uint32_t
getChildCount(const IORegistryPlane * plane) const1849 IORegistryEntry::getChildCount( const IORegistryPlane * plane ) const
1850 {
1851 	OSArray * links;
1852 	uint32_t  count = 0;
1853 
1854 	RLOCK;
1855 	links = getChildSetReference( plane );
1856 	if (links) {
1857 		count = links->getCount();
1858 	}
1859 	UNLOCK;
1860 
1861 	return count;
1862 }
1863 
1864 IORegistryEntry *
copyChildEntry(const IORegistryPlane * plane) const1865 IORegistryEntry::copyChildEntry(
1866 	const IORegistryPlane * plane ) const
1867 {
1868 	IORegistryEntry *   entry = NULL;
1869 	OSArray *           links;
1870 
1871 	RLOCK;
1872 
1873 	if ((links = getChildSetReference( plane ))) {
1874 		entry = (IORegistryEntry *) links->getObject( 0 );
1875 		entry->retain();
1876 	}
1877 
1878 	UNLOCK;
1879 
1880 	return entry;
1881 }
1882 
1883 // FIXME: Implementation of this function is hidden from the static analyzer.
1884 // The analyzer is worried that this release might as well be the last release.
1885 // Feel free to remove the #ifndef and address the warning!
1886 // See also rdar://problem/63023165.
1887 #ifndef __clang_analyzer__
1888 IORegistryEntry *
getChildEntry(const IORegistryPlane * plane) const1889 IORegistryEntry::getChildEntry(
1890 	const IORegistryPlane * plane ) const
1891 {
1892 	IORegistryEntry * entry;
1893 
1894 	entry = copyChildEntry( plane );
1895 	if (entry) {
1896 		entry->release();
1897 	}
1898 
1899 	return entry;
1900 }
1901 #endif // __clang_analyzer__
1902 
1903 void
applyToChildren(IORegistryEntryApplierFunction applier,void * context,const IORegistryPlane * plane) const1904 IORegistryEntry::applyToChildren( IORegistryEntryApplierFunction applier,
1905     void * context,
1906     const IORegistryPlane * plane ) const
1907 {
1908 	OSArray *           array;
1909 	unsigned int        index;
1910 	IORegistryEntry *   next;
1911 
1912 	if (!plane) {
1913 		return;
1914 	}
1915 
1916 	RLOCK;
1917 	array = OSArray::withArray( getChildSetReference( plane ));
1918 	UNLOCK;
1919 	if (array) {
1920 		for (index = 0;
1921 		    (next = (IORegistryEntry *) array->getObject( index ));
1922 		    index++) {
1923 			(*applier)(next, context);
1924 		}
1925 		array->release();
1926 	}
1927 }
1928 
1929 void
applyToParents(IORegistryEntryApplierFunction applier,void * context,const IORegistryPlane * plane) const1930 IORegistryEntry::applyToParents( IORegistryEntryApplierFunction applier,
1931     void * context,
1932     const IORegistryPlane * plane ) const
1933 {
1934 	OSArray *           array;
1935 	unsigned int        index;
1936 	IORegistryEntry *   next;
1937 
1938 	if (!plane) {
1939 		return;
1940 	}
1941 
1942 	RLOCK;
1943 	array = OSArray::withArray( getParentSetReference( plane ));
1944 	UNLOCK;
1945 	if (array) {
1946 		for (index = 0;
1947 		    (next = (IORegistryEntry *) array->getObject( index ));
1948 		    index++) {
1949 			(*applier)(next, context);
1950 		}
1951 		array->release();
1952 	}
1953 }
1954 
1955 bool
isChild(IORegistryEntry * child,const IORegistryPlane * plane,bool onlyChild) const1956 IORegistryEntry::isChild( IORegistryEntry * child,
1957     const IORegistryPlane * plane,
1958     bool onlyChild ) const
1959 {
1960 	OSArray *   links;
1961 	bool        ret = false;
1962 
1963 	RLOCK;
1964 
1965 	if ((links = getChildSetReference( plane ))) {
1966 		if ((!onlyChild) || (1 == links->getCount())) {
1967 			ret = arrayMember( links, child );
1968 		}
1969 	}
1970 	if (ret && (links = child->getParentSetReference( plane ))) {
1971 		ret = arrayMember( links, this );
1972 	}
1973 
1974 	UNLOCK;
1975 
1976 	return ret;
1977 }
1978 
1979 bool
isParent(IORegistryEntry * parent,const IORegistryPlane * plane,bool onlyParent) const1980 IORegistryEntry::isParent( IORegistryEntry * parent,
1981     const IORegistryPlane * plane,
1982     bool onlyParent ) const
1983 {
1984 	OSArray *   links;
1985 	bool        ret = false;
1986 
1987 	RLOCK;
1988 
1989 	if ((links = getParentSetReference( plane ))) {
1990 		if ((!onlyParent) || (1 == links->getCount())) {
1991 			ret = arrayMember( links, parent );
1992 		}
1993 	}
1994 	if (ret && (links = parent->getChildSetReference( plane ))) {
1995 		ret = arrayMember( links, this );
1996 	}
1997 
1998 	UNLOCK;
1999 
2000 	return ret;
2001 }
2002 
2003 bool
inPlane(const IORegistryPlane * plane) const2004 IORegistryEntry::inPlane( const IORegistryPlane * plane ) const
2005 {
2006 	bool ret;
2007 
2008 	RLOCK;
2009 
2010 	if (plane) {
2011 		ret = (NULL != getParentSetReference( plane ));
2012 	} else {
2013 		// Check to see if this is in any plane.  If it is in a plane
2014 		// then the registryTable will contain a key with the ParentLinks
2015 		// suffix.  When we iterate over the keys looking for that suffix
2016 		ret = false;
2017 
2018 		OSCollectionIterator *iter =
2019 		    OSCollectionIterator::withCollection( registryTable());
2020 		if (iter) {
2021 			const OSSymbol *key;
2022 
2023 			while ((key = (OSSymbol *) iter->getNextObject())) {
2024 				size_t keysuffix;
2025 
2026 				// Get a pointer to this keys suffix
2027 				keysuffix = key->getLength();
2028 				if (keysuffix <= kIORegPlaneParentSuffixLen) {
2029 					continue;
2030 				}
2031 				keysuffix -= kIORegPlaneParentSuffixLen;
2032 				if (!strncmp(key->getCStringNoCopy() + keysuffix,
2033 				    kIORegPlaneParentSuffix,
2034 				    kIORegPlaneParentSuffixLen + 1)) {
2035 					ret = true;
2036 					break;
2037 				}
2038 			}
2039 			iter->release();
2040 		}
2041 	}
2042 
2043 	UNLOCK;
2044 
2045 	return ret;
2046 }
2047 
2048 bool
attachToParent(IORegistryEntry * parent,const IORegistryPlane * plane)2049 IORegistryEntry::attachToParent( IORegistryEntry * parent,
2050     const IORegistryPlane * plane )
2051 {
2052 	OSArray *   links;
2053 	bool        ret;
2054 	bool        needParent;
2055 	bool        traceName = false;
2056 
2057 	if (this == parent) {
2058 		return false;
2059 	}
2060 
2061 	WLOCK;
2062 
2063 	if (!reserved->fRegistryEntryID) {
2064 		reserved->fRegistryEntryID = ++gIORegistryLastID;
2065 		traceName = (0 != gIOKitTrace);
2066 	}
2067 
2068 	ret = makeLink( parent, kParentSetIndex, plane );
2069 
2070 	if ((links = parent->getChildSetReference( plane ))) {
2071 		needParent = (false == arrayMember( links, this ));
2072 	} else {
2073 		needParent = true;
2074 	}
2075 
2076 	UNLOCK;
2077 
2078 	if (traceName) {
2079 		uint64_t str_id = 0;
2080 		uint64_t __unused regID = getRegistryEntryID();
2081 		kernel_debug_string(IODBG_IOREGISTRY(IOREGISTRYENTRY_NAME_STRING), &str_id, getName());
2082 		KERNEL_DEBUG_CONSTANT(IODBG_IOREGISTRY(IOREGISTRYENTRY_NAME),
2083 		    (uintptr_t) regID,
2084 		    (uintptr_t) (regID >> 32),
2085 		    (uintptr_t) str_id,
2086 		    (uintptr_t) (str_id >> 32),
2087 		    0);
2088 	}
2089 
2090 	PLOCK;
2091 
2092 	// Mark any collections in the property list as immutable
2093 	OSDictionary *ptable = getPropertyTable();
2094 	OSCollectionIterator *iter =
2095 	    OSCollectionIterator::withCollection( ptable );
2096 	if (iter) {
2097 		const OSSymbol *key;
2098 
2099 		while ((key = (OSSymbol *) iter->getNextObject())) {
2100 			// Is object for key a collection?
2101 			OSCollection *coll =
2102 			    OSDynamicCast( OSCollection, ptable->getObject( key ));
2103 
2104 			if (coll) {
2105 				// Yup so mark it as immutable
2106 				coll->setOptions( OSCollection::kMASK,
2107 				    OSCollection::kImmutable );
2108 			}
2109 		}
2110 		iter->release();
2111 	}
2112 
2113 	PUNLOCK;
2114 
2115 	if (needParent) {
2116 		ret &= parent->attachToChild( this, plane );
2117 	}
2118 
2119 	return ret;
2120 }
2121 
2122 uint64_t
getRegistryEntryID(void)2123 IORegistryEntry::getRegistryEntryID( void )
2124 {
2125 	if (reserved) {
2126 		return reserved->fRegistryEntryID;
2127 	} else {
2128 		return 0;
2129 	}
2130 }
2131 
2132 bool
attachToChild(IORegistryEntry * child,const IORegistryPlane * plane)2133 IORegistryEntry::attachToChild( IORegistryEntry * child,
2134     const IORegistryPlane * plane )
2135 {
2136 	OSArray *   links;
2137 	bool        ret;
2138 	bool        needChild;
2139 
2140 	if (this == child) {
2141 		return false;
2142 	}
2143 
2144 	WLOCK;
2145 
2146 	ret = makeLink( child, kChildSetIndex, plane );
2147 
2148 	if ((links = child->getParentSetReference( plane ))) {
2149 		needChild = (false == arrayMember( links, this ));
2150 	} else {
2151 		needChild = true;
2152 	}
2153 
2154 	UNLOCK;
2155 
2156 	if (needChild) {
2157 		ret &= child->attachToParent( this, plane );
2158 	}
2159 
2160 	return ret;
2161 }
2162 
2163 void
detachFromParent(IORegistryEntry * parent,const IORegistryPlane * plane)2164 IORegistryEntry::detachFromParent( IORegistryEntry * parent,
2165     const IORegistryPlane * plane )
2166 {
2167 	OSArray *   links;
2168 	bool        needParent;
2169 
2170 	WLOCK;
2171 
2172 	parent->retain();
2173 
2174 	breakLink( parent, kParentSetIndex, plane );
2175 
2176 	if ((links = parent->getChildSetReference( plane ))) {
2177 		needParent = arrayMember( links, this );
2178 	} else {
2179 		needParent = false;
2180 	}
2181 
2182 //    parent->breakLink( this, kChildSetIndex, plane );
2183 
2184 	UNLOCK;
2185 
2186 	if (needParent) {
2187 		parent->detachFromChild( this, plane );
2188 	}
2189 
2190 	parent->release();
2191 }
2192 
2193 void
detachFromChild(IORegistryEntry * child,const IORegistryPlane * plane)2194 IORegistryEntry::detachFromChild( IORegistryEntry * child,
2195     const IORegistryPlane * plane )
2196 {
2197 	OSArray *           links;
2198 	bool        needChild;
2199 
2200 	WLOCK;
2201 
2202 	child->retain();
2203 
2204 	breakLink( child, kChildSetIndex, plane );
2205 
2206 	if ((links = child->getParentSetReference( plane ))) {
2207 		needChild = arrayMember( links, this );
2208 	} else {
2209 		needChild = false;
2210 	}
2211 
2212 	UNLOCK;
2213 
2214 	if (needChild) {
2215 		child->detachFromParent( this, plane );
2216 	}
2217 
2218 	child->release();
2219 }
2220 
2221 void
detachAbove(const IORegistryPlane * plane)2222 IORegistryEntry::detachAbove( const IORegistryPlane * plane )
2223 {
2224 	IORegistryEntry *   parent;
2225 
2226 	retain();
2227 	while ((parent = copyParentEntry( plane ))) {
2228 		detachFromParent( parent, plane );
2229 		parent->release();
2230 	}
2231 	release();
2232 }
2233 
2234 void
detachAll(const IORegistryPlane * plane)2235 IORegistryEntry::detachAll( const IORegistryPlane * plane )
2236 {
2237 	OSOrderedSet *              all;
2238 	IORegistryEntry *           next;
2239 	IORegistryIterator *        regIter;
2240 
2241 	regIter = IORegistryIterator::iterateOver( this, plane, true );
2242 	if (NULL == regIter) {
2243 		return;
2244 	}
2245 	all = regIter->iterateAll();
2246 	regIter->release();
2247 
2248 	detachAbove( plane );
2249 	if (all) {
2250 		while ((next = (IORegistryEntry *) all->getLastObject())) {
2251 			next->retain();
2252 			all->removeObject(next);
2253 
2254 			next->detachAbove( plane );
2255 			next->release();
2256 		}
2257 		all->release();
2258 	}
2259 }
2260 
2261 unsigned int
getDepth(const IORegistryPlane * plane) const2262 IORegistryEntry::getDepth( const IORegistryPlane * plane ) const
2263 {
2264 	unsigned int                depth = 1;
2265 	OSArray *                   parents;
2266 	unsigned int                oneDepth, maxParentDepth, count;
2267 	IORegistryEntry *           one;
2268 	const IORegistryEntry *     next;
2269 	unsigned int                index;
2270 
2271 	RLOCK;
2272 
2273 	next = this;
2274 	while ((parents = next->getParentSetReference( plane ))) {
2275 		count = parents->getCount();
2276 		if (0 == count) {
2277 			break;
2278 		}
2279 		if (1 == count) {
2280 			depth++;
2281 			next = (IORegistryEntry *) parents->getObject( 0 );
2282 		} else {
2283 			// painful
2284 			maxParentDepth = 0;
2285 			for (index = 0;
2286 			    (one = (IORegistryEntry *) parents->getObject( index ));
2287 			    index++) {
2288 				oneDepth = one->getDepth( plane );
2289 				if (oneDepth > maxParentDepth) {
2290 					maxParentDepth = oneDepth;
2291 				}
2292 			}
2293 			depth += maxParentDepth;
2294 			break;
2295 		}
2296 	}
2297 
2298 	UNLOCK;
2299 
2300 	return depth;
2301 }
2302 
2303 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2304 
2305 #undef super
2306 #define super OSIterator
2307 
2308 OSDefineMetaClassAndStructors(IORegistryIterator, OSIterator)
2309 
2310 enum { kIORegistryIteratorInvalidFlag = 0x80000000 };
2311 
2312 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2313 
2314 IORegistryIterator *
iterateOver(IORegistryEntry * root,const IORegistryPlane * plane,IOOptionBits options)2315 IORegistryIterator::iterateOver( IORegistryEntry * root,
2316     const IORegistryPlane * plane,
2317     IOOptionBits options )
2318 {
2319 	IORegistryIterator *        create;
2320 
2321 	if (NULL == root) {
2322 		return NULL;
2323 	}
2324 	if (NULL == plane) {
2325 		return NULL;
2326 	}
2327 
2328 	create = new IORegistryIterator;
2329 	if (create) {
2330 		if (create->init()) {
2331 			root->retain();
2332 			create->root = root;
2333 			create->where = &create->start;
2334 			create->start.current = root;
2335 			create->plane = plane;
2336 			create->options = options & ~kIORegistryIteratorInvalidFlag;
2337 		} else {
2338 			create->release();
2339 			create = NULL;
2340 		}
2341 	}
2342 	return create;
2343 }
2344 
2345 IORegistryIterator *
iterateOver(const IORegistryPlane * plane,IOOptionBits options)2346 IORegistryIterator::iterateOver( const IORegistryPlane * plane,
2347     IOOptionBits options )
2348 {
2349 	return iterateOver( gRegistryRoot, plane, options );
2350 }
2351 
2352 bool
isValid(void)2353 IORegistryIterator::isValid( void )
2354 {
2355 	bool                ok;
2356 	IORegCursor *       next;
2357 
2358 	next = where;
2359 
2360 	RLOCK;
2361 
2362 	ok = (0 == (kIORegistryIteratorInvalidFlag & options));
2363 
2364 	while (ok && next) {
2365 		if (where->iter) {
2366 			ok = where->iter->isValid();
2367 		}
2368 		next = next->next;
2369 	}
2370 	UNLOCK;
2371 
2372 	return ok;
2373 }
2374 
2375 void
enterEntry(const IORegistryPlane * enterPlane)2376 IORegistryIterator::enterEntry( const IORegistryPlane * enterPlane )
2377 {
2378 	IORegCursor *       prev;
2379 
2380 	prev = where;
2381 	where = IOMallocType(IORegCursor);
2382 	assert( where);
2383 
2384 	if (where) {
2385 		where->iter = NULL;
2386 		where->next = prev;
2387 		where->current = prev->current;
2388 		plane = enterPlane;
2389 	}
2390 }
2391 
2392 void
enterEntry(void)2393 IORegistryIterator::enterEntry( void )
2394 {
2395 	enterEntry( plane );
2396 }
2397 
2398 bool
exitEntry(void)2399 IORegistryIterator::exitEntry( void )
2400 {
2401 	IORegCursor *       gone;
2402 
2403 	if (where->iter) {
2404 		where->iter->release();
2405 		where->iter = NULL;
2406 		if (where->current) {// && (where != &start))
2407 			where->current->release();
2408 		}
2409 	}
2410 
2411 	if (where != &start) {
2412 		gone = where;
2413 		where = gone->next;
2414 		IOFreeType(gone, IORegCursor);
2415 		return true;
2416 	} else {
2417 		return false;
2418 	}
2419 }
2420 
2421 void
reset(void)2422 IORegistryIterator::reset( void )
2423 {
2424 	while (exitEntry()) {
2425 	}
2426 
2427 	if (done) {
2428 		done->release();
2429 		done = NULL;
2430 	}
2431 
2432 	where->current = root;
2433 	options &= ~kIORegistryIteratorInvalidFlag;
2434 }
2435 
2436 void
free(void)2437 IORegistryIterator::free( void )
2438 {
2439 	reset();
2440 
2441 	if (root) {
2442 		root->release();
2443 	}
2444 
2445 	super::free();
2446 }
2447 
2448 
2449 IORegistryEntry *
getNextObjectFlat(void)2450 IORegistryIterator::getNextObjectFlat( void )
2451 {
2452 	IORegistryEntry *   next = NULL;
2453 	OSArray *           links = NULL;
2454 
2455 	RLOCK;
2456 
2457 	if ((NULL == where->iter)) {
2458 		// just entered - create new iter
2459 		if (isValid()
2460 		    && where->current
2461 		    && (links = ((options & kIORegistryIterateParents) ?
2462 		    where->current->getParentSetReference( plane ) :
2463 		    where->current->getChildSetReference( plane )))) {
2464 			where->iter = OSCollectionIterator::withCollection( links );
2465 		}
2466 	} else
2467 	// next sibling - release current
2468 	if (where->current) {
2469 		where->current->release();
2470 	}
2471 
2472 	if (where->iter) {
2473 		next = (IORegistryEntry *) where->iter->getNextObject();
2474 
2475 		if (next) {
2476 			next->retain();
2477 		} else if (!where->iter->isValid()) {
2478 			options |= kIORegistryIteratorInvalidFlag;
2479 		}
2480 	}
2481 
2482 	where->current = next;
2483 
2484 	UNLOCK;
2485 
2486 	return next;
2487 }
2488 
2489 IORegistryEntry *
getNextObjectRecursive(void)2490 IORegistryIterator::getNextObjectRecursive( void )
2491 {
2492 	IORegistryEntry *   next;
2493 
2494 	do{
2495 		next = getNextObjectFlat();
2496 	} while ((NULL == next) && exitEntry());
2497 
2498 	if (next) {
2499 		if (NULL == done) {
2500 			done = OSOrderedSet::withCapacity( 10 );
2501 		}
2502 		if (done->setObject((OSObject *) next)) {
2503 			// done set didn't contain this one, so recurse
2504 			enterEntry();
2505 		}
2506 	}
2507 	return next;
2508 }
2509 
2510 IORegistryEntry *
getNextObject(void)2511 IORegistryIterator::getNextObject( void )
2512 {
2513 	if (options & kIORegistryIterateRecursively) {
2514 		return getNextObjectRecursive();
2515 	} else {
2516 		return getNextObjectFlat();
2517 	}
2518 }
2519 
2520 IORegistryEntry *
getCurrentEntry(void)2521 IORegistryIterator::getCurrentEntry( void )
2522 {
2523 	if (isValid()) {
2524 		return where->current;
2525 	} else {
2526 		return NULL;
2527 	}
2528 }
2529 
2530 OSOrderedSet *
iterateAll(void)2531 IORegistryIterator::iterateAll( void )
2532 {
2533 	reset();
2534 	while (getNextObjectRecursive()) {
2535 	}
2536 	if (done) {
2537 		done->retain();
2538 	}
2539 	return done;
2540 }
2541 
2542 #if __LP64__
2543 OSMetaClassDefineReservedUnused(IORegistryEntry, 0);
2544 OSMetaClassDefineReservedUnused(IORegistryEntry, 1);
2545 OSMetaClassDefineReservedUnused(IORegistryEntry, 2);
2546 OSMetaClassDefineReservedUnused(IORegistryEntry, 3);
2547 OSMetaClassDefineReservedUnused(IORegistryEntry, 4);
2548 OSMetaClassDefineReservedUnused(IORegistryEntry, 5);
2549 #else
2550 OSMetaClassDefineReservedUsedX86(IORegistryEntry, 0);
2551 OSMetaClassDefineReservedUsedX86(IORegistryEntry, 1);
2552 OSMetaClassDefineReservedUsedX86(IORegistryEntry, 2);
2553 OSMetaClassDefineReservedUsedX86(IORegistryEntry, 3);
2554 OSMetaClassDefineReservedUsedX86(IORegistryEntry, 4);
2555 OSMetaClassDefineReservedUsedX86(IORegistryEntry, 5);
2556 #endif
2557 OSMetaClassDefineReservedUnused(IORegistryEntry, 6);
2558 OSMetaClassDefineReservedUnused(IORegistryEntry, 7);
2559 OSMetaClassDefineReservedUnused(IORegistryEntry, 8);
2560 OSMetaClassDefineReservedUnused(IORegistryEntry, 9);
2561 OSMetaClassDefineReservedUnused(IORegistryEntry, 10);
2562 OSMetaClassDefineReservedUnused(IORegistryEntry, 11);
2563 OSMetaClassDefineReservedUnused(IORegistryEntry, 12);
2564 OSMetaClassDefineReservedUnused(IORegistryEntry, 13);
2565 OSMetaClassDefineReservedUnused(IORegistryEntry, 14);
2566 OSMetaClassDefineReservedUnused(IORegistryEntry, 15);
2567 OSMetaClassDefineReservedUnused(IORegistryEntry, 16);
2568 OSMetaClassDefineReservedUnused(IORegistryEntry, 17);
2569 OSMetaClassDefineReservedUnused(IORegistryEntry, 18);
2570 OSMetaClassDefineReservedUnused(IORegistryEntry, 19);
2571 OSMetaClassDefineReservedUnused(IORegistryEntry, 20);
2572 OSMetaClassDefineReservedUnused(IORegistryEntry, 21);
2573 OSMetaClassDefineReservedUnused(IORegistryEntry, 22);
2574 OSMetaClassDefineReservedUnused(IORegistryEntry, 23);
2575 OSMetaClassDefineReservedUnused(IORegistryEntry, 24);
2576 OSMetaClassDefineReservedUnused(IORegistryEntry, 25);
2577 OSMetaClassDefineReservedUnused(IORegistryEntry, 26);
2578 OSMetaClassDefineReservedUnused(IORegistryEntry, 27);
2579 OSMetaClassDefineReservedUnused(IORegistryEntry, 28);
2580 OSMetaClassDefineReservedUnused(IORegistryEntry, 29);
2581 OSMetaClassDefineReservedUnused(IORegistryEntry, 30);
2582 OSMetaClassDefineReservedUnused(IORegistryEntry, 31);
2583 
2584 /* inline function implementation */
2585 OSDictionary *
getPropertyTable(void) const2586 IORegistryEntry::getPropertyTable( void ) const
2587 {
2588 	return fPropertyTable;
2589 }
2590