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