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