xref: /xnu-11215/iokit/Kernel/IOStatistics.cpp (revision e6231be0)
1855239e5SApple OSS Distributions /*
2855239e5SApple OSS Distributions  * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
3855239e5SApple OSS Distributions  *
4855239e5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5855239e5SApple OSS Distributions  *
6855239e5SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7855239e5SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8855239e5SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9855239e5SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10855239e5SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11855239e5SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12855239e5SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13855239e5SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14855239e5SApple OSS Distributions  *
15855239e5SApple OSS Distributions  * Please obtain a copy of the License at
16855239e5SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17855239e5SApple OSS Distributions  *
18855239e5SApple OSS Distributions  * The Original Code and all software distributed under the License are
19855239e5SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20855239e5SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21855239e5SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22855239e5SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23855239e5SApple OSS Distributions  * Please see the License for the specific language governing rights and
24855239e5SApple OSS Distributions  * limitations under the License.
25855239e5SApple OSS Distributions  *
26855239e5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27855239e5SApple OSS Distributions  */
28855239e5SApple OSS Distributions 
29855239e5SApple OSS Distributions #include <sys/sysctl.h>
3088cc0b97SApple OSS Distributions #include <kern/backtrace.h>
31855239e5SApple OSS Distributions #include <kern/host.h>
32186b8fceSApple OSS Distributions #include <kern/zalloc.h>
33855239e5SApple OSS Distributions 
34855239e5SApple OSS Distributions #include <IOKit/system.h>
35855239e5SApple OSS Distributions #include <libkern/c++/OSKext.h>
36855239e5SApple OSS Distributions #include <libkern/OSAtomic.h>
37855239e5SApple OSS Distributions 
38855239e5SApple OSS Distributions #include <IOKit/IOStatisticsPrivate.h>
39855239e5SApple OSS Distributions #include <IOKit/IOUserClient.h>
40855239e5SApple OSS Distributions #include <IOKit/IOEventSource.h>
41855239e5SApple OSS Distributions #include <IOKit/IOKitDebug.h>
42855239e5SApple OSS Distributions 
43855239e5SApple OSS Distributions #if IOKITSTATS
44855239e5SApple OSS Distributions bool IOStatistics::enabled = false;
45855239e5SApple OSS Distributions 
46855239e5SApple OSS Distributions uint32_t IOStatistics::sequenceID = 0;
47855239e5SApple OSS Distributions 
48855239e5SApple OSS Distributions uint32_t IOStatistics::lastClassIndex = 0;
49855239e5SApple OSS Distributions uint32_t IOStatistics::lastKextIndex = 0;
50855239e5SApple OSS Distributions 
51855239e5SApple OSS Distributions uint32_t IOStatistics::loadedKexts = 0;
52855239e5SApple OSS Distributions uint32_t IOStatistics::registeredClasses = 0;
53855239e5SApple OSS Distributions uint32_t IOStatistics::registeredCounters = 0;
54855239e5SApple OSS Distributions uint32_t IOStatistics::registeredWorkloops = 0;
55855239e5SApple OSS Distributions 
56855239e5SApple OSS Distributions uint32_t IOStatistics::attachedEventSources = 0;
57855239e5SApple OSS Distributions 
58855239e5SApple OSS Distributions IOWorkLoopDependency *IOStatistics::nextWorkLoopDependency = NULL;
59855239e5SApple OSS Distributions 
60855239e5SApple OSS Distributions /* Logging */
61855239e5SApple OSS Distributions 
62855239e5SApple OSS Distributions #define LOG_LEVEL 0
63855239e5SApple OSS Distributions 
64855239e5SApple OSS Distributions #define LOG(level, format, ...) \
65855239e5SApple OSS Distributions do { \
66855239e5SApple OSS Distributions 	if (level <= LOG_LEVEL) \
67855239e5SApple OSS Distributions 	        printf(format, ##__VA_ARGS__); \
68855239e5SApple OSS Distributions } while (0)
69855239e5SApple OSS Distributions 
70855239e5SApple OSS Distributions /* Locks */
71855239e5SApple OSS Distributions 
72855239e5SApple OSS Distributions IORWLock *IOStatistics::lock = NULL;
73855239e5SApple OSS Distributions 
74855239e5SApple OSS Distributions /* Kext tree */
75855239e5SApple OSS Distributions 
76855239e5SApple OSS Distributions KextNode *IOStatistics::kextHint = NULL;
77855239e5SApple OSS Distributions 
78855239e5SApple OSS Distributions IOStatistics::KextTreeHead IOStatistics::kextHead = RB_INITIALIZER(&IOStatistics::kextHead);
79855239e5SApple OSS Distributions 
80a5e72196SApple OSS Distributions int
kextNodeCompare(KextNode * e1,KextNode * e2)81a5e72196SApple OSS Distributions IOStatistics::kextNodeCompare(KextNode *e1, KextNode *e2)
82855239e5SApple OSS Distributions {
83a5e72196SApple OSS Distributions 	if (e1->kext < e2->kext) {
84855239e5SApple OSS Distributions 		return -1;
85a5e72196SApple OSS Distributions 	} else if (e1->kext > e2->kext) {
86855239e5SApple OSS Distributions 		return 1;
87a5e72196SApple OSS Distributions 	} else {
88855239e5SApple OSS Distributions 		return 0;
89855239e5SApple OSS Distributions 	}
90a5e72196SApple OSS Distributions }
91855239e5SApple OSS Distributions 
92855239e5SApple OSS Distributions RB_GENERATE(IOStatistics::KextTree, KextNode, link, kextNodeCompare);
93855239e5SApple OSS Distributions 
94855239e5SApple OSS Distributions /* Kext tree ordered by address */
95855239e5SApple OSS Distributions 
96855239e5SApple OSS Distributions IOStatistics::KextAddressTreeHead IOStatistics::kextAddressHead = RB_INITIALIZER(&IOStatistics::kextAddressHead);
97855239e5SApple OSS Distributions 
98a5e72196SApple OSS Distributions int
kextAddressNodeCompare(KextNode * e1,KextNode * e2)99a5e72196SApple OSS Distributions IOStatistics::kextAddressNodeCompare(KextNode *e1, KextNode *e2)
100855239e5SApple OSS Distributions {
101a5e72196SApple OSS Distributions 	if (e1->address < e2->address) {
102855239e5SApple OSS Distributions 		return -1;
103a5e72196SApple OSS Distributions 	} else if (e1->address > e2->address) {
104855239e5SApple OSS Distributions 		return 1;
105a5e72196SApple OSS Distributions 	} else {
106855239e5SApple OSS Distributions 		return 0;
107855239e5SApple OSS Distributions 	}
108a5e72196SApple OSS Distributions }
109855239e5SApple OSS Distributions 
110855239e5SApple OSS Distributions RB_GENERATE(IOStatistics::KextAddressTree, KextNode, addressLink, kextAddressNodeCompare);
111855239e5SApple OSS Distributions 
112855239e5SApple OSS Distributions /* Class tree */
113855239e5SApple OSS Distributions 
114855239e5SApple OSS Distributions IOStatistics::ClassTreeHead IOStatistics::classHead = RB_INITIALIZER(&IOStatistics::classHead);
115855239e5SApple OSS Distributions 
116a5e72196SApple OSS Distributions int
classNodeCompare(ClassNode * e1,ClassNode * e2)117a5e72196SApple OSS Distributions IOStatistics::classNodeCompare(ClassNode *e1, ClassNode *e2)
118a5e72196SApple OSS Distributions {
119a5e72196SApple OSS Distributions 	if (e1->metaClass < e2->metaClass) {
120855239e5SApple OSS Distributions 		return -1;
121a5e72196SApple OSS Distributions 	} else if (e1->metaClass > e2->metaClass) {
122855239e5SApple OSS Distributions 		return 1;
123a5e72196SApple OSS Distributions 	} else {
124855239e5SApple OSS Distributions 		return 0;
125855239e5SApple OSS Distributions 	}
126a5e72196SApple OSS Distributions }
127855239e5SApple OSS Distributions 
128855239e5SApple OSS Distributions RB_GENERATE(IOStatistics::ClassTree, ClassNode, tLink, classNodeCompare);
129855239e5SApple OSS Distributions 
130855239e5SApple OSS Distributions /* Workloop dependencies */
131855239e5SApple OSS Distributions 
132a5e72196SApple OSS Distributions int
loadTagCompare(IOWorkLoopDependency * e1,IOWorkLoopDependency * e2)133a5e72196SApple OSS Distributions IOWorkLoopCounter::loadTagCompare(IOWorkLoopDependency *e1, IOWorkLoopDependency *e2)
134a5e72196SApple OSS Distributions {
135a5e72196SApple OSS Distributions 	if (e1->loadTag < e2->loadTag) {
136855239e5SApple OSS Distributions 		return -1;
137a5e72196SApple OSS Distributions 	} else if (e1->loadTag > e2->loadTag) {
138855239e5SApple OSS Distributions 		return 1;
139a5e72196SApple OSS Distributions 	} else {
140855239e5SApple OSS Distributions 		return 0;
141855239e5SApple OSS Distributions 	}
142a5e72196SApple OSS Distributions }
143855239e5SApple OSS Distributions 
144855239e5SApple OSS Distributions RB_GENERATE(IOWorkLoopCounter::DependencyTree, IOWorkLoopDependency, link, IOWorkLoopCounter::loadTagCompare);
145855239e5SApple OSS Distributions 
146855239e5SApple OSS Distributions /* sysctl stuff */
147855239e5SApple OSS Distributions 
148855239e5SApple OSS Distributions static int
oid_sysctl(__unused struct sysctl_oid * oidp,__unused void * arg1,int arg2,struct sysctl_req * req)149855239e5SApple OSS Distributions oid_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1, int arg2, struct sysctl_req *req)
150855239e5SApple OSS Distributions {
151855239e5SApple OSS Distributions 	int error = EINVAL;
152855239e5SApple OSS Distributions 	uint32_t request = arg2;
153855239e5SApple OSS Distributions 
154*e6231be0SApple OSS Distributions 	if (!IOStatistics::isEnabled()) {
155*e6231be0SApple OSS Distributions 		return ENOENT;
156*e6231be0SApple OSS Distributions 	}
157*e6231be0SApple OSS Distributions 
158a5e72196SApple OSS Distributions 	switch (request) {
159855239e5SApple OSS Distributions 	case kIOStatisticsGeneral:
160855239e5SApple OSS Distributions 		error = IOStatistics::getStatistics(req);
161855239e5SApple OSS Distributions 		break;
162855239e5SApple OSS Distributions 	case kIOStatisticsWorkLoop:
163855239e5SApple OSS Distributions 		error = IOStatistics::getWorkLoopStatistics(req);
164855239e5SApple OSS Distributions 		break;
165855239e5SApple OSS Distributions 	case kIOStatisticsUserClient:
166855239e5SApple OSS Distributions 		error = IOStatistics::getUserClientStatistics(req);
167855239e5SApple OSS Distributions 		break;
168855239e5SApple OSS Distributions 	default:
169855239e5SApple OSS Distributions 		break;
170855239e5SApple OSS Distributions 	}
171855239e5SApple OSS Distributions 
172855239e5SApple OSS Distributions 	return error;
173855239e5SApple OSS Distributions }
174855239e5SApple OSS Distributions 
175a5e72196SApple OSS Distributions SYSCTL_NODE(_debug, OID_AUTO, iokit_statistics, CTLFLAG_RW | CTLFLAG_LOCKED, NULL, "IOStatistics");
176855239e5SApple OSS Distributions 
177855239e5SApple OSS Distributions static SYSCTL_PROC(_debug_iokit_statistics, OID_AUTO, general,
178*e6231be0SApple OSS Distributions     CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
179a5e72196SApple OSS Distributions     NULL, kIOStatisticsGeneral, oid_sysctl, "S", "");
180855239e5SApple OSS Distributions 
181855239e5SApple OSS Distributions static SYSCTL_PROC(_debug_iokit_statistics, OID_AUTO, workloop,
182*e6231be0SApple OSS Distributions     CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
183a5e72196SApple OSS Distributions     NULL, kIOStatisticsWorkLoop, oid_sysctl, "S", "");
184855239e5SApple OSS Distributions 
185855239e5SApple OSS Distributions static SYSCTL_PROC(_debug_iokit_statistics, OID_AUTO, userclient,
186*e6231be0SApple OSS Distributions     CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
187a5e72196SApple OSS Distributions     NULL, kIOStatisticsUserClient, oid_sysctl, "S", "");
188855239e5SApple OSS Distributions 
189*e6231be0SApple OSS Distributions 
190a5e72196SApple OSS Distributions void
initialize()191a5e72196SApple OSS Distributions IOStatistics::initialize()
192855239e5SApple OSS Distributions {
193855239e5SApple OSS Distributions 	if (enabled) {
194855239e5SApple OSS Distributions 		return;
195855239e5SApple OSS Distributions 	}
196855239e5SApple OSS Distributions 
197d0c1fef6SApple OSS Distributions 	/* Only enabled if the boot argument is set. */
198855239e5SApple OSS Distributions 	if (!(kIOStatistics & gIOKitDebug)) {
199855239e5SApple OSS Distributions 		return;
200855239e5SApple OSS Distributions 	}
201855239e5SApple OSS Distributions 
202855239e5SApple OSS Distributions 	lock = IORWLockAlloc();
203855239e5SApple OSS Distributions 	if (!lock) {
204855239e5SApple OSS Distributions 		return;
205855239e5SApple OSS Distributions 	}
206855239e5SApple OSS Distributions 
207*e6231be0SApple OSS Distributions 	nextWorkLoopDependency = kalloc_type(IOWorkLoopDependency, Z_WAITOK);
208855239e5SApple OSS Distributions 	if (!nextWorkLoopDependency) {
209855239e5SApple OSS Distributions 		return;
210855239e5SApple OSS Distributions 	}
211855239e5SApple OSS Distributions 
212855239e5SApple OSS Distributions 	enabled = true;
213855239e5SApple OSS Distributions }
214855239e5SApple OSS Distributions 
215a5e72196SApple OSS Distributions void
onKextLoad(OSKext * kext,kmod_info_t * kmod_info)216a5e72196SApple OSS Distributions IOStatistics::onKextLoad(OSKext *kext, kmod_info_t *kmod_info)
217855239e5SApple OSS Distributions {
218855239e5SApple OSS Distributions 	KextNode *ke;
219855239e5SApple OSS Distributions 
220855239e5SApple OSS Distributions 	assert(kext && kmod_info);
221855239e5SApple OSS Distributions 
222855239e5SApple OSS Distributions 	if (!enabled) {
223855239e5SApple OSS Distributions 		return;
224855239e5SApple OSS Distributions 	}
225855239e5SApple OSS Distributions 
226855239e5SApple OSS Distributions 	LOG(1, "IOStatistics::onKextLoad: %s, tag %d, address 0x%llx, address end 0x%llx\n",
227855239e5SApple OSS Distributions 	    kext->getIdentifierCString(), kmod_info->id, (uint64_t)kmod_info->address, (uint64_t)(kmod_info->address + kmod_info->size));
228855239e5SApple OSS Distributions 
229*e6231be0SApple OSS Distributions 	ke = kalloc_type(KextNode, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
230855239e5SApple OSS Distributions 	if (!ke) {
231855239e5SApple OSS Distributions 		return;
232855239e5SApple OSS Distributions 	}
233855239e5SApple OSS Distributions 
234855239e5SApple OSS Distributions 	ke->kext = kext;
235855239e5SApple OSS Distributions 	ke->loadTag = kmod_info->id;
236855239e5SApple OSS Distributions 	ke->address = kmod_info->address;
237855239e5SApple OSS Distributions 	ke->address_end = kmod_info->address + kmod_info->size;
238855239e5SApple OSS Distributions 
239855239e5SApple OSS Distributions 	SLIST_INIT(&ke->classList);
240855239e5SApple OSS Distributions 	TAILQ_INIT(&ke->userClientCallList);
241855239e5SApple OSS Distributions 
242855239e5SApple OSS Distributions 	IORWLockWrite(lock);
243855239e5SApple OSS Distributions 
244855239e5SApple OSS Distributions 	RB_INSERT(KextTree, &kextHead, ke);
245855239e5SApple OSS Distributions 	RB_INSERT(KextAddressTree, &kextAddressHead, ke);
246855239e5SApple OSS Distributions 
247855239e5SApple OSS Distributions 	sequenceID++;
248855239e5SApple OSS Distributions 	loadedKexts++;
249855239e5SApple OSS Distributions 	lastKextIndex++;
250855239e5SApple OSS Distributions 
251855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
252855239e5SApple OSS Distributions }
253855239e5SApple OSS Distributions 
254a5e72196SApple OSS Distributions void
onKextUnload(OSKext * kext)255a5e72196SApple OSS Distributions IOStatistics::onKextUnload(OSKext *kext)
256855239e5SApple OSS Distributions {
257855239e5SApple OSS Distributions 	KextNode sought, *found;
258855239e5SApple OSS Distributions 
259855239e5SApple OSS Distributions 	assert(kext);
260855239e5SApple OSS Distributions 
261855239e5SApple OSS Distributions 	if (!enabled) {
262855239e5SApple OSS Distributions 		return;
263855239e5SApple OSS Distributions 	}
264855239e5SApple OSS Distributions 
265855239e5SApple OSS Distributions 	LOG(1, "IOStatistics::onKextUnload: %s\n", kext->getIdentifierCString());
266855239e5SApple OSS Distributions 
267855239e5SApple OSS Distributions 	IORWLockWrite(lock);
268855239e5SApple OSS Distributions 
269855239e5SApple OSS Distributions 	sought.kext = kext;
270855239e5SApple OSS Distributions 	found = RB_FIND(KextTree, &kextHead, &sought);
271855239e5SApple OSS Distributions 	if (found) {
272855239e5SApple OSS Distributions 		IOWorkLoopCounter *wlc;
273855239e5SApple OSS Distributions 		IOUserClientProcessEntry *uce;
274855239e5SApple OSS Distributions 
275186b8fceSApple OSS Distributions 		/* Disconnect workloop counters; cleanup takes place in unregisterWorkLoop() */
276855239e5SApple OSS Distributions 		while ((wlc = SLIST_FIRST(&found->workLoopList))) {
277855239e5SApple OSS Distributions 			SLIST_REMOVE_HEAD(&found->workLoopList, link);
278186b8fceSApple OSS Distributions 			wlc->parentKext = NULL;
279855239e5SApple OSS Distributions 		}
280855239e5SApple OSS Distributions 
281855239e5SApple OSS Distributions 		/* Free up the user client list */
282855239e5SApple OSS Distributions 		while ((uce = TAILQ_FIRST(&found->userClientCallList))) {
283855239e5SApple OSS Distributions 			TAILQ_REMOVE(&found->userClientCallList, uce, link);
284*e6231be0SApple OSS Distributions 			kfree_type(IOUserClientProcessEntry, uce);
285855239e5SApple OSS Distributions 		}
286855239e5SApple OSS Distributions 
287855239e5SApple OSS Distributions 		/* Remove from kext trees */
288855239e5SApple OSS Distributions 		RB_REMOVE(KextTree, &kextHead, found);
289855239e5SApple OSS Distributions 		RB_REMOVE(KextAddressTree, &kextAddressHead, found);
290855239e5SApple OSS Distributions 
291855239e5SApple OSS Distributions 		/*
292855239e5SApple OSS Distributions 		 * Clear a matching kextHint to avoid use after free in
293855239e5SApple OSS Distributions 		 * onClassAdded() for a class add after a KEXT unload.
294855239e5SApple OSS Distributions 		 */
295855239e5SApple OSS Distributions 		if (found == kextHint) {
296855239e5SApple OSS Distributions 			kextHint = NULL;
297855239e5SApple OSS Distributions 		}
298855239e5SApple OSS Distributions 
299855239e5SApple OSS Distributions 		/* Finally, free the class node */
300*e6231be0SApple OSS Distributions 		kfree_type(KextNode, found);
301855239e5SApple OSS Distributions 
302855239e5SApple OSS Distributions 		sequenceID++;
303855239e5SApple OSS Distributions 		loadedKexts--;
304a5e72196SApple OSS Distributions 	} else {
305855239e5SApple OSS Distributions 		panic("IOStatistics::onKextUnload: cannot find kext: %s", kext->getIdentifierCString());
306855239e5SApple OSS Distributions 	}
307855239e5SApple OSS Distributions 
308855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
309855239e5SApple OSS Distributions }
310855239e5SApple OSS Distributions 
311a5e72196SApple OSS Distributions void
onClassAdded(OSKext * parentKext,OSMetaClass * metaClass)312a5e72196SApple OSS Distributions IOStatistics::onClassAdded(OSKext *parentKext, OSMetaClass *metaClass)
313855239e5SApple OSS Distributions {
314855239e5SApple OSS Distributions 	ClassNode *ce;
315855239e5SApple OSS Distributions 	KextNode soughtKext, *foundKext = NULL;
316855239e5SApple OSS Distributions 
317855239e5SApple OSS Distributions 	assert(parentKext && metaClass);
318855239e5SApple OSS Distributions 
319855239e5SApple OSS Distributions 	if (!enabled) {
320855239e5SApple OSS Distributions 		return;
321855239e5SApple OSS Distributions 	}
322855239e5SApple OSS Distributions 
323855239e5SApple OSS Distributions 	LOG(1, "IOStatistics::onClassAdded: %s\n", metaClass->getClassName());
324855239e5SApple OSS Distributions 
325*e6231be0SApple OSS Distributions 	ce = kalloc_type(ClassNode, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
326855239e5SApple OSS Distributions 	if (!ce) {
327855239e5SApple OSS Distributions 		return;
328855239e5SApple OSS Distributions 	}
329855239e5SApple OSS Distributions 
330855239e5SApple OSS Distributions 	IORWLockWrite(lock);
331855239e5SApple OSS Distributions 
332855239e5SApple OSS Distributions 	/* Hinted? */
333855239e5SApple OSS Distributions 	if (kextHint && kextHint->kext == parentKext) {
334855239e5SApple OSS Distributions 		foundKext = kextHint;
335a5e72196SApple OSS Distributions 	} else {
336855239e5SApple OSS Distributions 		soughtKext.kext = parentKext;
337855239e5SApple OSS Distributions 		foundKext = RB_FIND(KextTree, &kextHead, &soughtKext);
338855239e5SApple OSS Distributions 	}
339855239e5SApple OSS Distributions 
340855239e5SApple OSS Distributions 	if (foundKext) {
341855239e5SApple OSS Distributions 		ClassNode soughtClass, *foundClass = NULL;
342855239e5SApple OSS Distributions 		const OSMetaClass *superClass;
343855239e5SApple OSS Distributions 
344855239e5SApple OSS Distributions 		ce->metaClass = metaClass;
345855239e5SApple OSS Distributions 		ce->classID = lastClassIndex++;
346855239e5SApple OSS Distributions 		ce->parentKext = foundKext;
347855239e5SApple OSS Distributions 
348855239e5SApple OSS Distributions 		/* Has superclass? */
349855239e5SApple OSS Distributions 		superClass = ce->metaClass->getSuperClass();
350855239e5SApple OSS Distributions 		if (superClass) {
351855239e5SApple OSS Distributions 			soughtClass.metaClass = superClass;
352855239e5SApple OSS Distributions 			foundClass = RB_FIND(ClassTree, &classHead, &soughtClass);
353855239e5SApple OSS Distributions 		}
354855239e5SApple OSS Distributions 		ce->superClassID = foundClass ? foundClass->classID : (uint32_t)(-1);
355855239e5SApple OSS Distributions 
356855239e5SApple OSS Distributions 		SLIST_INIT(&ce->counterList);
357855239e5SApple OSS Distributions 		SLIST_INIT(&ce->userClientList);
358855239e5SApple OSS Distributions 
359855239e5SApple OSS Distributions 		RB_INSERT(ClassTree, &classHead, ce);
360855239e5SApple OSS Distributions 		SLIST_INSERT_HEAD(&foundKext->classList, ce, lLink);
361855239e5SApple OSS Distributions 
362855239e5SApple OSS Distributions 		foundKext->classes++;
363855239e5SApple OSS Distributions 
364855239e5SApple OSS Distributions 		kextHint = foundKext;
365855239e5SApple OSS Distributions 
366855239e5SApple OSS Distributions 		sequenceID++;
367855239e5SApple OSS Distributions 		registeredClasses++;
368a5e72196SApple OSS Distributions 	} else {
369855239e5SApple OSS Distributions 		panic("IOStatistics::onClassAdded: cannot find parent kext: %s", parentKext->getIdentifierCString());
370855239e5SApple OSS Distributions 	}
371855239e5SApple OSS Distributions 
372855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
373855239e5SApple OSS Distributions }
374855239e5SApple OSS Distributions 
375a5e72196SApple OSS Distributions void
onClassRemoved(OSKext * parentKext,OSMetaClass * metaClass)376a5e72196SApple OSS Distributions IOStatistics::onClassRemoved(OSKext *parentKext, OSMetaClass *metaClass)
377855239e5SApple OSS Distributions {
378855239e5SApple OSS Distributions 	ClassNode sought, *found;
379855239e5SApple OSS Distributions 
380855239e5SApple OSS Distributions 	assert(parentKext && metaClass);
381855239e5SApple OSS Distributions 
382855239e5SApple OSS Distributions 	if (!enabled) {
383855239e5SApple OSS Distributions 		return;
384855239e5SApple OSS Distributions 	}
385855239e5SApple OSS Distributions 
386855239e5SApple OSS Distributions 	LOG(1, "IOStatistics::onClassRemoved: %s\n", metaClass->getClassName());
387855239e5SApple OSS Distributions 
388855239e5SApple OSS Distributions 	IORWLockWrite(lock);
389855239e5SApple OSS Distributions 
390855239e5SApple OSS Distributions 	sought.metaClass = metaClass;
391855239e5SApple OSS Distributions 	found = RB_FIND(ClassTree, &classHead, &sought);
392855239e5SApple OSS Distributions 	if (found) {
393855239e5SApple OSS Distributions 		IOEventSourceCounter *esc;
394855239e5SApple OSS Distributions 		IOUserClientCounter *ucc;
395855239e5SApple OSS Distributions 
396855239e5SApple OSS Distributions 		/* Free up the list of counters */
397855239e5SApple OSS Distributions 		while ((esc = SLIST_FIRST(&found->counterList))) {
398855239e5SApple OSS Distributions 			SLIST_REMOVE_HEAD(&found->counterList, link);
399*e6231be0SApple OSS Distributions 			kfree_type(IOEventSourceCounter, esc);
400855239e5SApple OSS Distributions 		}
401855239e5SApple OSS Distributions 
402855239e5SApple OSS Distributions 		/* Free up the user client list */
403855239e5SApple OSS Distributions 		while ((ucc = SLIST_FIRST(&found->userClientList))) {
404855239e5SApple OSS Distributions 			SLIST_REMOVE_HEAD(&found->userClientList, link);
405*e6231be0SApple OSS Distributions 			kfree_type(IOUserClientCounter, ucc);
406855239e5SApple OSS Distributions 		}
407855239e5SApple OSS Distributions 
408855239e5SApple OSS Distributions 		/* Remove from class tree */
409855239e5SApple OSS Distributions 		RB_REMOVE(ClassTree, &classHead, found);
410855239e5SApple OSS Distributions 
411855239e5SApple OSS Distributions 		/* Remove from parent */
412855239e5SApple OSS Distributions 		SLIST_REMOVE(&found->parentKext->classList, found, ClassNode, lLink);
413855239e5SApple OSS Distributions 
414855239e5SApple OSS Distributions 		/* Finally, free the class node */
415*e6231be0SApple OSS Distributions 		kfree_type(ClassNode, found);
416855239e5SApple OSS Distributions 
417855239e5SApple OSS Distributions 		sequenceID++;
418855239e5SApple OSS Distributions 		registeredClasses--;
419a5e72196SApple OSS Distributions 	} else {
420855239e5SApple OSS Distributions 		panic("IOStatistics::onClassRemoved: cannot find class: %s", metaClass->getClassName());
421855239e5SApple OSS Distributions 	}
422855239e5SApple OSS Distributions 
423855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
424855239e5SApple OSS Distributions }
425855239e5SApple OSS Distributions 
426a5e72196SApple OSS Distributions IOEventSourceCounter *
registerEventSource(OSObject * inOwner)427a5e72196SApple OSS Distributions IOStatistics::registerEventSource(OSObject *inOwner)
428855239e5SApple OSS Distributions {
429855239e5SApple OSS Distributions 	IOEventSourceCounter *counter = NULL;
430855239e5SApple OSS Distributions 	ClassNode sought, *found = NULL;
431855239e5SApple OSS Distributions 	boolean_t createDummyCounter = FALSE;
432855239e5SApple OSS Distributions 
433855239e5SApple OSS Distributions 	assert(inOwner);
434855239e5SApple OSS Distributions 
435855239e5SApple OSS Distributions 	if (!enabled) {
436855239e5SApple OSS Distributions 		return NULL;
437855239e5SApple OSS Distributions 	}
438855239e5SApple OSS Distributions 
439*e6231be0SApple OSS Distributions 	counter = kalloc_type(IOEventSourceCounter, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
440855239e5SApple OSS Distributions 	if (!counter) {
441855239e5SApple OSS Distributions 		return NULL;
442855239e5SApple OSS Distributions 	}
443855239e5SApple OSS Distributions 
444855239e5SApple OSS Distributions 	IORWLockWrite(lock);
445855239e5SApple OSS Distributions 
446855239e5SApple OSS Distributions 	/* Workaround for <rdar://problem/7158117> - create a dummy counter when inOwner is bad.
447855239e5SApple OSS Distributions 	 * We use retainCount here as our best indication that the pointer is awry.
448855239e5SApple OSS Distributions 	 */
449855239e5SApple OSS Distributions 	if (inOwner->retainCount > 0xFFFFFF) {
450855239e5SApple OSS Distributions 		kprintf("IOStatistics::registerEventSource - bad metaclass %p\n", inOwner);
451855239e5SApple OSS Distributions 		createDummyCounter = TRUE;
452a5e72196SApple OSS Distributions 	} else {
453855239e5SApple OSS Distributions 		sought.metaClass = inOwner->getMetaClass();
454855239e5SApple OSS Distributions 		found = RB_FIND(ClassTree, &classHead, &sought);
455855239e5SApple OSS Distributions 	}
456855239e5SApple OSS Distributions 
457855239e5SApple OSS Distributions 	if (found) {
458855239e5SApple OSS Distributions 		counter->parentClass = found;
459855239e5SApple OSS Distributions 		SLIST_INSERT_HEAD(&found->counterList, counter, link);
460855239e5SApple OSS Distributions 		registeredCounters++;
461855239e5SApple OSS Distributions 	}
462855239e5SApple OSS Distributions 
463855239e5SApple OSS Distributions 	if (!(createDummyCounter || found)) {
464855239e5SApple OSS Distributions 		panic("IOStatistics::registerEventSource: cannot find parent class: %s", inOwner->getMetaClass()->getClassName());
465855239e5SApple OSS Distributions 	}
466855239e5SApple OSS Distributions 
467855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
468855239e5SApple OSS Distributions 
469855239e5SApple OSS Distributions 	return counter;
470855239e5SApple OSS Distributions }
471855239e5SApple OSS Distributions 
472a5e72196SApple OSS Distributions void
unregisterEventSource(IOEventSourceCounter * counter)473a5e72196SApple OSS Distributions IOStatistics::unregisterEventSource(IOEventSourceCounter *counter)
474855239e5SApple OSS Distributions {
475855239e5SApple OSS Distributions 	if (!counter) {
476855239e5SApple OSS Distributions 		return;
477855239e5SApple OSS Distributions 	}
478855239e5SApple OSS Distributions 
479855239e5SApple OSS Distributions 	IORWLockWrite(lock);
480855239e5SApple OSS Distributions 
481855239e5SApple OSS Distributions 	if (counter->parentClass) {
482855239e5SApple OSS Distributions 		SLIST_REMOVE(&counter->parentClass->counterList, counter, IOEventSourceCounter, link);
483855239e5SApple OSS Distributions 		registeredCounters--;
484855239e5SApple OSS Distributions 	}
485*e6231be0SApple OSS Distributions 	kfree_type(IOEventSourceCounter, counter);
486855239e5SApple OSS Distributions 
487855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
488855239e5SApple OSS Distributions }
489855239e5SApple OSS Distributions 
490a5e72196SApple OSS Distributions IOWorkLoopCounter*
registerWorkLoop(IOWorkLoop * workLoop)491a5e72196SApple OSS Distributions IOStatistics::registerWorkLoop(IOWorkLoop *workLoop)
492855239e5SApple OSS Distributions {
493855239e5SApple OSS Distributions 	IOWorkLoopCounter *counter = NULL;
494855239e5SApple OSS Distributions 	KextNode *found;
495855239e5SApple OSS Distributions 
496855239e5SApple OSS Distributions 	assert(workLoop);
497855239e5SApple OSS Distributions 
498855239e5SApple OSS Distributions 	if (!enabled) {
499855239e5SApple OSS Distributions 		return NULL;
500855239e5SApple OSS Distributions 	}
501855239e5SApple OSS Distributions 
502*e6231be0SApple OSS Distributions 	counter = kalloc_type(IOWorkLoopCounter, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
503855239e5SApple OSS Distributions 	if (!counter) {
504855239e5SApple OSS Distributions 		return NULL;
505855239e5SApple OSS Distributions 	}
506855239e5SApple OSS Distributions 
507855239e5SApple OSS Distributions 	found = getKextNodeFromBacktrace(TRUE);
508855239e5SApple OSS Distributions 	if (!found) {
509855239e5SApple OSS Distributions 		panic("IOStatistics::registerWorkLoop: cannot find parent kext");
510855239e5SApple OSS Distributions 	}
511855239e5SApple OSS Distributions 
512855239e5SApple OSS Distributions 	counter->parentKext = found;
513855239e5SApple OSS Distributions 	counter->workLoop = workLoop;
514855239e5SApple OSS Distributions 	RB_INIT(&counter->dependencyHead);
515855239e5SApple OSS Distributions 	SLIST_INSERT_HEAD(&found->workLoopList, counter, link);
516855239e5SApple OSS Distributions 	registeredWorkloops++;
517855239e5SApple OSS Distributions 
518855239e5SApple OSS Distributions 	releaseKextNode(found);
519855239e5SApple OSS Distributions 
520855239e5SApple OSS Distributions 	return counter;
521855239e5SApple OSS Distributions }
522855239e5SApple OSS Distributions 
523a5e72196SApple OSS Distributions void
unregisterWorkLoop(IOWorkLoopCounter * counter)524a5e72196SApple OSS Distributions IOStatistics::unregisterWorkLoop(IOWorkLoopCounter *counter)
525855239e5SApple OSS Distributions {
526855239e5SApple OSS Distributions 	if (!counter) {
527855239e5SApple OSS Distributions 		return;
528855239e5SApple OSS Distributions 	}
529855239e5SApple OSS Distributions 
530855239e5SApple OSS Distributions 	IORWLockWrite(lock);
531186b8fceSApple OSS Distributions 	if (counter->parentKext) {
532855239e5SApple OSS Distributions 		SLIST_REMOVE(&counter->parentKext->workLoopList, counter, IOWorkLoopCounter, link);
533186b8fceSApple OSS Distributions 	}
534*e6231be0SApple OSS Distributions 	kfree_type(IOWorkLoopCounter, counter);
535855239e5SApple OSS Distributions 	registeredWorkloops--;
536855239e5SApple OSS Distributions 
537855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
538855239e5SApple OSS Distributions }
539855239e5SApple OSS Distributions 
540a5e72196SApple OSS Distributions IOUserClientCounter *
registerUserClient(IOUserClient * userClient)541a5e72196SApple OSS Distributions IOStatistics::registerUserClient(IOUserClient *userClient)
542855239e5SApple OSS Distributions {
543855239e5SApple OSS Distributions 	ClassNode sought, *found;
544855239e5SApple OSS Distributions 	IOUserClientCounter *counter = NULL;
545855239e5SApple OSS Distributions 
546855239e5SApple OSS Distributions 	assert(userClient);
547855239e5SApple OSS Distributions 
548855239e5SApple OSS Distributions 	if (!enabled) {
549855239e5SApple OSS Distributions 		return NULL;
550855239e5SApple OSS Distributions 	}
551855239e5SApple OSS Distributions 
552*e6231be0SApple OSS Distributions 	counter = kalloc_type(IOUserClientCounter, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
553855239e5SApple OSS Distributions 	if (!counter) {
554855239e5SApple OSS Distributions 		return NULL;
555855239e5SApple OSS Distributions 	}
556855239e5SApple OSS Distributions 
557855239e5SApple OSS Distributions 	IORWLockWrite(lock);
558855239e5SApple OSS Distributions 
559855239e5SApple OSS Distributions 	sought.metaClass = userClient->getMetaClass();
560855239e5SApple OSS Distributions 
561855239e5SApple OSS Distributions 	found = RB_FIND(ClassTree, &classHead, &sought);
562855239e5SApple OSS Distributions 	if (found) {
563855239e5SApple OSS Distributions 		counter->parentClass = found;
564855239e5SApple OSS Distributions 		SLIST_INSERT_HEAD(&found->userClientList, counter, link);
565a5e72196SApple OSS Distributions 	} else {
566855239e5SApple OSS Distributions 		panic("IOStatistics::registerUserClient: cannot find parent class: %s", sought.metaClass->getClassName());
567855239e5SApple OSS Distributions 	}
568855239e5SApple OSS Distributions 
569855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
570855239e5SApple OSS Distributions 
571855239e5SApple OSS Distributions 	return counter;
572855239e5SApple OSS Distributions }
573855239e5SApple OSS Distributions 
574a5e72196SApple OSS Distributions void
unregisterUserClient(IOUserClientCounter * counter)575a5e72196SApple OSS Distributions IOStatistics::unregisterUserClient(IOUserClientCounter *counter)
576855239e5SApple OSS Distributions {
577855239e5SApple OSS Distributions 	if (!counter) {
578855239e5SApple OSS Distributions 		return;
579855239e5SApple OSS Distributions 	}
580855239e5SApple OSS Distributions 
581855239e5SApple OSS Distributions 	IORWLockWrite(lock);
582855239e5SApple OSS Distributions 
583855239e5SApple OSS Distributions 	SLIST_REMOVE(&counter->parentClass->userClientList, counter, IOUserClientCounter, link);
584*e6231be0SApple OSS Distributions 	kfree_type(IOUserClientCounter, counter);
585855239e5SApple OSS Distributions 
586855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
587855239e5SApple OSS Distributions }
588855239e5SApple OSS Distributions 
589a5e72196SApple OSS Distributions void
attachWorkLoopEventSource(IOWorkLoopCounter * wlc,IOEventSourceCounter * esc)590a5e72196SApple OSS Distributions IOStatistics::attachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc)
591855239e5SApple OSS Distributions {
592855239e5SApple OSS Distributions 	if (!wlc) {
593855239e5SApple OSS Distributions 		return;
594855239e5SApple OSS Distributions 	}
595855239e5SApple OSS Distributions 
596855239e5SApple OSS Distributions 	IORWLockWrite(lock);
597855239e5SApple OSS Distributions 
598855239e5SApple OSS Distributions 	if (!nextWorkLoopDependency) {
599855239e5SApple OSS Distributions 		return;
600855239e5SApple OSS Distributions 	}
601855239e5SApple OSS Distributions 
602855239e5SApple OSS Distributions 	attachedEventSources++;
603855239e5SApple OSS Distributions 	wlc->attachedEventSources++;
604855239e5SApple OSS Distributions 
605855239e5SApple OSS Distributions 	/* Track the kext dependency */
606855239e5SApple OSS Distributions 	nextWorkLoopDependency->loadTag = esc->parentClass->parentKext->loadTag;
607855239e5SApple OSS Distributions 	if (NULL == RB_INSERT(IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead, nextWorkLoopDependency)) {
608*e6231be0SApple OSS Distributions 		nextWorkLoopDependency = kalloc_type(IOWorkLoopDependency, Z_WAITOK);
609855239e5SApple OSS Distributions 	}
610855239e5SApple OSS Distributions 
611855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
612855239e5SApple OSS Distributions }
613855239e5SApple OSS Distributions 
614a5e72196SApple OSS Distributions void
detachWorkLoopEventSource(IOWorkLoopCounter * wlc,IOEventSourceCounter * esc)615a5e72196SApple OSS Distributions IOStatistics::detachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc)
616855239e5SApple OSS Distributions {
617855239e5SApple OSS Distributions 	IOWorkLoopDependency sought, *found;
618855239e5SApple OSS Distributions 
619855239e5SApple OSS Distributions 	if (!wlc) {
620855239e5SApple OSS Distributions 		return;
621855239e5SApple OSS Distributions 	}
622855239e5SApple OSS Distributions 
623855239e5SApple OSS Distributions 	IORWLockWrite(lock);
624855239e5SApple OSS Distributions 
625855239e5SApple OSS Distributions 	attachedEventSources--;
626855239e5SApple OSS Distributions 	wlc->attachedEventSources--;
627855239e5SApple OSS Distributions 
628855239e5SApple OSS Distributions 	sought.loadTag = esc->parentClass->parentKext->loadTag;
629855239e5SApple OSS Distributions 
630855239e5SApple OSS Distributions 	found = RB_FIND(IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead, &sought);
631855239e5SApple OSS Distributions 	if (found) {
632855239e5SApple OSS Distributions 		RB_REMOVE(IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead, found);
633*e6231be0SApple OSS Distributions 		kfree_type(IOWorkLoopDependency, found);
634855239e5SApple OSS Distributions 	}
635855239e5SApple OSS Distributions 
636855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
637855239e5SApple OSS Distributions }
638855239e5SApple OSS Distributions 
639a5e72196SApple OSS Distributions int
getStatistics(sysctl_req * req)640a5e72196SApple OSS Distributions IOStatistics::getStatistics(sysctl_req *req)
641855239e5SApple OSS Distributions {
642855239e5SApple OSS Distributions 	int error;
643855239e5SApple OSS Distributions 	uint32_t calculatedSize, size;
644855239e5SApple OSS Distributions 	char *buffer, *ptr;
645855239e5SApple OSS Distributions 	IOStatisticsHeader *header;
646855239e5SApple OSS Distributions 
647855239e5SApple OSS Distributions 	assert(IOStatistics::enabled && req);
648855239e5SApple OSS Distributions 
649855239e5SApple OSS Distributions 	IORWLockRead(IOStatistics::lock);
650855239e5SApple OSS Distributions 
651855239e5SApple OSS Distributions 	/* Work out how much we need to allocate. IOStatisticsKext is of variable size. */
652855239e5SApple OSS Distributions 	calculatedSize = sizeof(IOStatisticsHeader) +
653855239e5SApple OSS Distributions 	    sizeof(IOStatisticsGlobal) +
654855239e5SApple OSS Distributions 	    (sizeof(IOStatisticsKext) * loadedKexts) + (sizeof(uint32_t) * registeredClasses) +
655855239e5SApple OSS Distributions 	    (sizeof(IOStatisticsMemory) * loadedKexts) +
656855239e5SApple OSS Distributions 	    (sizeof(IOStatisticsClass) * registeredClasses) +
657855239e5SApple OSS Distributions 	    (sizeof(IOStatisticsCounter) * registeredClasses) +
658855239e5SApple OSS Distributions 	    (sizeof(IOStatisticsKextIdentifier) * loadedKexts) +
659855239e5SApple OSS Distributions 	    (sizeof(IOStatisticsClassName) * registeredClasses);
660855239e5SApple OSS Distributions 
661855239e5SApple OSS Distributions 	/* Size request? */
662855239e5SApple OSS Distributions 	if (req->oldptr == USER_ADDR_NULL) {
663855239e5SApple OSS Distributions 		error = SYSCTL_OUT(req, NULL, calculatedSize);
664855239e5SApple OSS Distributions 		goto exit;
665855239e5SApple OSS Distributions 	}
666855239e5SApple OSS Distributions 
667855239e5SApple OSS Distributions 	/* Read only */
668855239e5SApple OSS Distributions 	if (req->newptr != USER_ADDR_NULL) {
669855239e5SApple OSS Distributions 		error = EPERM;
670855239e5SApple OSS Distributions 		goto exit;
671855239e5SApple OSS Distributions 	}
672855239e5SApple OSS Distributions 
673*e6231be0SApple OSS Distributions 	buffer = (char*)kalloc_data(calculatedSize, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
674855239e5SApple OSS Distributions 	if (!buffer) {
675855239e5SApple OSS Distributions 		error = ENOMEM;
676855239e5SApple OSS Distributions 		goto exit;
677855239e5SApple OSS Distributions 	}
678855239e5SApple OSS Distributions 
679855239e5SApple OSS Distributions 	ptr = buffer;
680855239e5SApple OSS Distributions 
681855239e5SApple OSS Distributions 	header = (IOStatisticsHeader*)((void*)ptr);
682855239e5SApple OSS Distributions 
683855239e5SApple OSS Distributions 	header->sig = IOSTATISTICS_SIG;
684855239e5SApple OSS Distributions 	header->ver = IOSTATISTICS_VER;
685855239e5SApple OSS Distributions 
686855239e5SApple OSS Distributions 	header->seq = sequenceID;
687855239e5SApple OSS Distributions 
688855239e5SApple OSS Distributions 	ptr += sizeof(IOStatisticsHeader);
689855239e5SApple OSS Distributions 
690855239e5SApple OSS Distributions 	/* Global data - seq, timers, interrupts, etc) */
691855239e5SApple OSS Distributions 	header->globalStatsOffset = sizeof(IOStatisticsHeader);
692855239e5SApple OSS Distributions 	size = copyGlobalStatistics((IOStatisticsGlobal*)((void*)ptr));
693855239e5SApple OSS Distributions 	ptr += size;
694855239e5SApple OSS Distributions 
695855239e5SApple OSS Distributions 	/* Kext statistics */
696855239e5SApple OSS Distributions 	header->kextStatsOffset = header->globalStatsOffset + size;
697855239e5SApple OSS Distributions 	size = copyKextStatistics((IOStatisticsKext*)((void*)ptr));
698855239e5SApple OSS Distributions 	ptr += size;
699855239e5SApple OSS Distributions 
700855239e5SApple OSS Distributions 	/* Memory allocation info */
701855239e5SApple OSS Distributions 	header->memoryStatsOffset = header->kextStatsOffset + size;
702855239e5SApple OSS Distributions 	size = copyMemoryStatistics((IOStatisticsMemory*)((void*)ptr));
703855239e5SApple OSS Distributions 	ptr += size;
704855239e5SApple OSS Distributions 
705855239e5SApple OSS Distributions 	/* Class statistics */
706855239e5SApple OSS Distributions 	header->classStatsOffset = header->memoryStatsOffset + size;
707855239e5SApple OSS Distributions 	size = copyClassStatistics((IOStatisticsClass*)((void*)ptr));
708855239e5SApple OSS Distributions 	ptr += size;
709855239e5SApple OSS Distributions 
710855239e5SApple OSS Distributions 	/* Dynamic class counter data */
711855239e5SApple OSS Distributions 	header->counterStatsOffset = header->classStatsOffset + size;
712855239e5SApple OSS Distributions 	size = copyCounterStatistics((IOStatisticsCounter*)((void*)ptr));
713855239e5SApple OSS Distributions 	ptr += size;
714855239e5SApple OSS Distributions 
715855239e5SApple OSS Distributions 	/* Kext identifiers */
716855239e5SApple OSS Distributions 	header->kextIdentifiersOffset = header->counterStatsOffset + size;
717855239e5SApple OSS Distributions 	size = copyKextIdentifiers((IOStatisticsKextIdentifier*)((void*)ptr));
718855239e5SApple OSS Distributions 	ptr += size;
719855239e5SApple OSS Distributions 
720855239e5SApple OSS Distributions 	/* Class names */
721855239e5SApple OSS Distributions 	header->classNamesOffset = header->kextIdentifiersOffset + size;
722855239e5SApple OSS Distributions 	size = copyClassNames((IOStatisticsClassName*)ptr);
723855239e5SApple OSS Distributions 	ptr += size;
724855239e5SApple OSS Distributions 
725855239e5SApple OSS Distributions 	LOG(2, "IOStatistics::getStatistics - calculatedSize 0x%x, kexts 0x%x, classes 0x%x.\n",
726855239e5SApple OSS Distributions 	    calculatedSize, loadedKexts, registeredClasses);
727855239e5SApple OSS Distributions 
728855239e5SApple OSS Distributions 	assert((uint32_t)(ptr - buffer) == calculatedSize );
729855239e5SApple OSS Distributions 
730855239e5SApple OSS Distributions 	error = SYSCTL_OUT(req, buffer, calculatedSize);
731855239e5SApple OSS Distributions 
732*e6231be0SApple OSS Distributions 	kfree_data(buffer, calculatedSize);
733855239e5SApple OSS Distributions 
734855239e5SApple OSS Distributions exit:
735855239e5SApple OSS Distributions 	IORWLockUnlock(IOStatistics::lock);
736855239e5SApple OSS Distributions 	return error;
737855239e5SApple OSS Distributions }
738855239e5SApple OSS Distributions 
739a5e72196SApple OSS Distributions int
getWorkLoopStatistics(sysctl_req * req)740a5e72196SApple OSS Distributions IOStatistics::getWorkLoopStatistics(sysctl_req *req)
741855239e5SApple OSS Distributions {
742855239e5SApple OSS Distributions 	int error;
743855239e5SApple OSS Distributions 	uint32_t calculatedSize, size;
744855239e5SApple OSS Distributions 	char *buffer;
745855239e5SApple OSS Distributions 	IOStatisticsWorkLoopHeader *header;
746855239e5SApple OSS Distributions 
747855239e5SApple OSS Distributions 	assert(IOStatistics::enabled && req);
748855239e5SApple OSS Distributions 
749855239e5SApple OSS Distributions 	IORWLockRead(IOStatistics::lock);
750855239e5SApple OSS Distributions 
751855239e5SApple OSS Distributions 	/* Approximate how much we need to allocate (worse case estimate) */
752855239e5SApple OSS Distributions 	calculatedSize = sizeof(IOStatisticsWorkLoop) * registeredWorkloops +
753855239e5SApple OSS Distributions 	    sizeof(uint32_t) * attachedEventSources;
754855239e5SApple OSS Distributions 
755855239e5SApple OSS Distributions 	/* Size request? */
756855239e5SApple OSS Distributions 	if (req->oldptr == USER_ADDR_NULL) {
757855239e5SApple OSS Distributions 		error = SYSCTL_OUT(req, NULL, calculatedSize);
758855239e5SApple OSS Distributions 		goto exit;
759855239e5SApple OSS Distributions 	}
760855239e5SApple OSS Distributions 
761855239e5SApple OSS Distributions 	/* Read only */
762855239e5SApple OSS Distributions 	if (req->newptr != USER_ADDR_NULL) {
763855239e5SApple OSS Distributions 		error = EPERM;
764855239e5SApple OSS Distributions 		goto exit;
765855239e5SApple OSS Distributions 	}
766855239e5SApple OSS Distributions 
767*e6231be0SApple OSS Distributions 	buffer = (char*)kalloc_data(calculatedSize, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
768855239e5SApple OSS Distributions 	if (!buffer) {
769855239e5SApple OSS Distributions 		error = ENOMEM;
770855239e5SApple OSS Distributions 		goto exit;
771855239e5SApple OSS Distributions 	}
772855239e5SApple OSS Distributions 	header = (IOStatisticsWorkLoopHeader*)((void*)buffer);
773855239e5SApple OSS Distributions 
774855239e5SApple OSS Distributions 	header->sig = IOSTATISTICS_SIG_WORKLOOP;
775855239e5SApple OSS Distributions 	header->ver = IOSTATISTICS_VER;
776855239e5SApple OSS Distributions 
777855239e5SApple OSS Distributions 	header->seq = sequenceID;
778855239e5SApple OSS Distributions 
779855239e5SApple OSS Distributions 	header->workloopCount = registeredWorkloops;
780855239e5SApple OSS Distributions 
781855239e5SApple OSS Distributions 	size = copyWorkLoopStatistics(&header->workLoopStats);
782855239e5SApple OSS Distributions 
783855239e5SApple OSS Distributions 	LOG(2, "IOStatistics::getWorkLoopStatistics: calculatedSize %d, size %d\n", calculatedSize, size);
784855239e5SApple OSS Distributions 
785855239e5SApple OSS Distributions 	assert( size <= calculatedSize );
786855239e5SApple OSS Distributions 
787855239e5SApple OSS Distributions 	error = SYSCTL_OUT(req, buffer, size);
788855239e5SApple OSS Distributions 
789*e6231be0SApple OSS Distributions 	kfree_data(buffer, calculatedSize);
790855239e5SApple OSS Distributions 
791855239e5SApple OSS Distributions exit:
792855239e5SApple OSS Distributions 	IORWLockUnlock(IOStatistics::lock);
793855239e5SApple OSS Distributions 	return error;
794855239e5SApple OSS Distributions }
795855239e5SApple OSS Distributions 
796a5e72196SApple OSS Distributions int
getUserClientStatistics(sysctl_req * req)797a5e72196SApple OSS Distributions IOStatistics::getUserClientStatistics(sysctl_req *req)
798855239e5SApple OSS Distributions {
799855239e5SApple OSS Distributions 	int error;
800855239e5SApple OSS Distributions 	uint32_t calculatedSize, size;
801855239e5SApple OSS Distributions 	char *buffer;
802855239e5SApple OSS Distributions 	uint32_t requestedLoadTag = 0;
803855239e5SApple OSS Distributions 	IOStatisticsUserClientHeader *header;
804855239e5SApple OSS Distributions 
805855239e5SApple OSS Distributions 	assert(IOStatistics::enabled && req);
806855239e5SApple OSS Distributions 
807855239e5SApple OSS Distributions 	IORWLockRead(IOStatistics::lock);
808855239e5SApple OSS Distributions 
809855239e5SApple OSS Distributions 	/* Work out how much we need to allocate */
810855239e5SApple OSS Distributions 	calculatedSize = sizeof(IOStatisticsUserClientHeader) +
811855239e5SApple OSS Distributions 	    sizeof(IOStatisticsUserClientCall) * IOKIT_STATISTICS_RECORDED_USERCLIENT_PROCS * loadedKexts;
812855239e5SApple OSS Distributions 
813855239e5SApple OSS Distributions 	/* Size request? */
814855239e5SApple OSS Distributions 	if (req->oldptr == USER_ADDR_NULL) {
815855239e5SApple OSS Distributions 		error = SYSCTL_OUT(req, NULL, calculatedSize);
816855239e5SApple OSS Distributions 		goto exit;
817855239e5SApple OSS Distributions 	}
818855239e5SApple OSS Distributions 
819855239e5SApple OSS Distributions 	/* Kext request (potentially) valid? */
820855239e5SApple OSS Distributions 	if (!req->newptr || req->newlen < sizeof(requestedLoadTag)) {
821855239e5SApple OSS Distributions 		error = EINVAL;
822855239e5SApple OSS Distributions 		goto exit;
823855239e5SApple OSS Distributions 	}
824855239e5SApple OSS Distributions 
82576e12aa3SApple OSS Distributions 	error = SYSCTL_IN(req, &requestedLoadTag, sizeof(requestedLoadTag));
82676e12aa3SApple OSS Distributions 	if (error) {
82776e12aa3SApple OSS Distributions 		goto exit;
82876e12aa3SApple OSS Distributions 	}
829855239e5SApple OSS Distributions 
830855239e5SApple OSS Distributions 	LOG(2, "IOStatistics::getUserClientStatistics - requesting kext w/load tag: %d\n", requestedLoadTag);
831855239e5SApple OSS Distributions 
832*e6231be0SApple OSS Distributions 	buffer = (char*)kalloc_data(calculatedSize, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
833855239e5SApple OSS Distributions 	if (!buffer) {
834855239e5SApple OSS Distributions 		error = ENOMEM;
835855239e5SApple OSS Distributions 		goto exit;
836855239e5SApple OSS Distributions 	}
837855239e5SApple OSS Distributions 	header = (IOStatisticsUserClientHeader*)((void*)buffer);
838855239e5SApple OSS Distributions 
839855239e5SApple OSS Distributions 	header->sig = IOSTATISTICS_SIG_USERCLIENT;
840855239e5SApple OSS Distributions 	header->ver = IOSTATISTICS_VER;
841855239e5SApple OSS Distributions 
842855239e5SApple OSS Distributions 	header->seq = sequenceID;
843855239e5SApple OSS Distributions 
844855239e5SApple OSS Distributions 	header->processes = 0;
845855239e5SApple OSS Distributions 
846855239e5SApple OSS Distributions 	size = copyUserClientStatistics(header, requestedLoadTag);
847855239e5SApple OSS Distributions 
848855239e5SApple OSS Distributions 	assert((sizeof(IOStatisticsUserClientHeader) + size) <= calculatedSize);
849855239e5SApple OSS Distributions 
850855239e5SApple OSS Distributions 	if (size) {
851855239e5SApple OSS Distributions 		error = SYSCTL_OUT(req, buffer, sizeof(IOStatisticsUserClientHeader) + size);
852a5e72196SApple OSS Distributions 	} else {
853855239e5SApple OSS Distributions 		error = EINVAL;
854855239e5SApple OSS Distributions 	}
855855239e5SApple OSS Distributions 
856*e6231be0SApple OSS Distributions 	kfree_data(buffer, calculatedSize);
857855239e5SApple OSS Distributions 
858855239e5SApple OSS Distributions exit:
859855239e5SApple OSS Distributions 	IORWLockUnlock(IOStatistics::lock);
860855239e5SApple OSS Distributions 	return error;
861855239e5SApple OSS Distributions }
862855239e5SApple OSS Distributions 
863a5e72196SApple OSS Distributions uint32_t
copyGlobalStatistics(IOStatisticsGlobal * stats)864a5e72196SApple OSS Distributions IOStatistics::copyGlobalStatistics(IOStatisticsGlobal *stats)
865855239e5SApple OSS Distributions {
866855239e5SApple OSS Distributions 	stats->kextCount = loadedKexts;
867855239e5SApple OSS Distributions 	stats->classCount = registeredClasses;
868855239e5SApple OSS Distributions 	stats->workloops = registeredWorkloops;
869855239e5SApple OSS Distributions 
870855239e5SApple OSS Distributions 	return sizeof(IOStatisticsGlobal);
871855239e5SApple OSS Distributions }
872855239e5SApple OSS Distributions 
873a5e72196SApple OSS Distributions uint32_t
copyKextStatistics(IOStatisticsKext * stats)874a5e72196SApple OSS Distributions IOStatistics::copyKextStatistics(IOStatisticsKext *stats)
875855239e5SApple OSS Distributions {
876855239e5SApple OSS Distributions 	KextNode *ke;
877855239e5SApple OSS Distributions 	ClassNode *ce;
878855239e5SApple OSS Distributions 	uint32_t index = 0;
879855239e5SApple OSS Distributions 
880855239e5SApple OSS Distributions 	RB_FOREACH(ke, KextTree, &kextHead) {
881855239e5SApple OSS Distributions 		stats->loadTag = ke->loadTag;
882855239e5SApple OSS Distributions 		ke->kext->getSizeInfo(&stats->loadSize, &stats->wiredSize);
883855239e5SApple OSS Distributions 
884855239e5SApple OSS Distributions 		stats->classes = ke->classes;
885855239e5SApple OSS Distributions 
886855239e5SApple OSS Distributions 		/* Append indices of owned classes */
887855239e5SApple OSS Distributions 		SLIST_FOREACH(ce, &ke->classList, lLink) {
888855239e5SApple OSS Distributions 			stats->classIndexes[index++] = ce->classID;
889855239e5SApple OSS Distributions 		}
890855239e5SApple OSS Distributions 
891855239e5SApple OSS Distributions 		stats = (IOStatisticsKext *)((void*)((char*)stats + sizeof(IOStatisticsKext) + (ke->classes * sizeof(uint32_t))));
892855239e5SApple OSS Distributions 	}
893855239e5SApple OSS Distributions 
894a5e72196SApple OSS Distributions 	return sizeof(IOStatisticsKext) * loadedKexts + sizeof(uint32_t) * registeredClasses;
895855239e5SApple OSS Distributions }
896855239e5SApple OSS Distributions 
897a5e72196SApple OSS Distributions uint32_t
copyMemoryStatistics(IOStatisticsMemory * stats)898a5e72196SApple OSS Distributions IOStatistics::copyMemoryStatistics(IOStatisticsMemory *stats)
899855239e5SApple OSS Distributions {
900855239e5SApple OSS Distributions 	KextNode *ke;
901855239e5SApple OSS Distributions 
902855239e5SApple OSS Distributions 	RB_FOREACH(ke, KextTree, &kextHead) {
903855239e5SApple OSS Distributions 		stats->allocatedSize = ke->memoryCounters[kIOStatisticsMalloc];
904855239e5SApple OSS Distributions 		stats->freedSize = ke->memoryCounters[kIOStatisticsFree];
905855239e5SApple OSS Distributions 		stats->allocatedAlignedSize = ke->memoryCounters[kIOStatisticsMallocAligned];
906855239e5SApple OSS Distributions 		stats->freedAlignedSize = ke->memoryCounters[kIOStatisticsFreeAligned];
907855239e5SApple OSS Distributions 		stats->allocatedContiguousSize = ke->memoryCounters[kIOStatisticsMallocContiguous];
908855239e5SApple OSS Distributions 		stats->freedContiguousSize = ke->memoryCounters[kIOStatisticsFreeContiguous];
909855239e5SApple OSS Distributions 		stats->allocatedPageableSize = ke->memoryCounters[kIOStatisticsMallocPageable];
910855239e5SApple OSS Distributions 		stats->freedPageableSize = ke->memoryCounters[kIOStatisticsFreePageable];
911855239e5SApple OSS Distributions 		stats++;
912855239e5SApple OSS Distributions 	}
913855239e5SApple OSS Distributions 
914a5e72196SApple OSS Distributions 	return sizeof(IOStatisticsMemory) * loadedKexts;
915855239e5SApple OSS Distributions }
916855239e5SApple OSS Distributions 
917a5e72196SApple OSS Distributions uint32_t
copyClassStatistics(IOStatisticsClass * stats)918a5e72196SApple OSS Distributions IOStatistics::copyClassStatistics(IOStatisticsClass *stats)
919855239e5SApple OSS Distributions {
920855239e5SApple OSS Distributions 	KextNode *ke;
921855239e5SApple OSS Distributions 	ClassNode *ce;
922855239e5SApple OSS Distributions 
923855239e5SApple OSS Distributions 	RB_FOREACH(ke, KextTree, &kextHead) {
924855239e5SApple OSS Distributions 		SLIST_FOREACH(ce, &ke->classList, lLink) {
925855239e5SApple OSS Distributions 			stats->classID = ce->classID;
926855239e5SApple OSS Distributions 			stats->superClassID = ce->superClassID;
927855239e5SApple OSS Distributions 			stats->classSize = ce->metaClass->getClassSize();
928855239e5SApple OSS Distributions 
929855239e5SApple OSS Distributions 			stats++;
930855239e5SApple OSS Distributions 		}
931855239e5SApple OSS Distributions 	}
932855239e5SApple OSS Distributions 
933855239e5SApple OSS Distributions 	return sizeof(IOStatisticsClass) * registeredClasses;
934855239e5SApple OSS Distributions }
935855239e5SApple OSS Distributions 
936a5e72196SApple OSS Distributions uint32_t
copyCounterStatistics(IOStatisticsCounter * stats)937a5e72196SApple OSS Distributions IOStatistics::copyCounterStatistics(IOStatisticsCounter *stats)
938855239e5SApple OSS Distributions {
939855239e5SApple OSS Distributions 	KextNode *ke;
940855239e5SApple OSS Distributions 	ClassNode *ce;
941855239e5SApple OSS Distributions 
942855239e5SApple OSS Distributions 	RB_FOREACH(ke, KextTree, &kextHead) {
943855239e5SApple OSS Distributions 		SLIST_FOREACH(ce, &ke->classList, lLink) {
944855239e5SApple OSS Distributions 			IOUserClientCounter *userClientCounter;
945855239e5SApple OSS Distributions 			IOEventSourceCounter *counter;
946855239e5SApple OSS Distributions 
947855239e5SApple OSS Distributions 			stats->classID = ce->classID;
948855239e5SApple OSS Distributions 			stats->classInstanceCount = ce->metaClass->getInstanceCount();
949855239e5SApple OSS Distributions 
950855239e5SApple OSS Distributions 			IOStatisticsUserClients *uc = &stats->userClientStatistics;
951855239e5SApple OSS Distributions 
952855239e5SApple OSS Distributions 			/* User client counters */
953855239e5SApple OSS Distributions 			SLIST_FOREACH(userClientCounter, &ce->userClientList, link) {
954855239e5SApple OSS Distributions 				uc->clientCalls += userClientCounter->clientCalls;
955855239e5SApple OSS Distributions 				uc->created++;
956855239e5SApple OSS Distributions 			}
957855239e5SApple OSS Distributions 
958855239e5SApple OSS Distributions 			IOStatisticsInterruptEventSources *iec = &stats->interruptEventSourceStatistics;
959855239e5SApple OSS Distributions 			IOStatisticsInterruptEventSources *fiec = &stats->filterInterruptEventSourceStatistics;
960855239e5SApple OSS Distributions 			IOStatisticsTimerEventSources *tec = &stats->timerEventSourceStatistics;
961855239e5SApple OSS Distributions 			IOStatisticsCommandGates *cgc = &stats->commandGateStatistics;
962855239e5SApple OSS Distributions 			IOStatisticsCommandQueues *cqc = &stats->commandQueueStatistics;
963855239e5SApple OSS Distributions 			IOStatisticsDerivedEventSources *dec = &stats->derivedEventSourceStatistics;
964855239e5SApple OSS Distributions 
965855239e5SApple OSS Distributions 			/* Event source counters */
966855239e5SApple OSS Distributions 			SLIST_FOREACH(counter, &ce->counterList, link) {
967855239e5SApple OSS Distributions 				switch (counter->type) {
968855239e5SApple OSS Distributions 				case kIOStatisticsInterruptEventSourceCounter:
969855239e5SApple OSS Distributions 					iec->created++;
970855239e5SApple OSS Distributions 					iec->produced += counter->u.interrupt.produced;
971855239e5SApple OSS Distributions 					iec->checksForWork += counter->u.interrupt.checksForWork;
972855239e5SApple OSS Distributions 					break;
973855239e5SApple OSS Distributions 				case kIOStatisticsFilterInterruptEventSourceCounter:
974855239e5SApple OSS Distributions 					fiec->created++;
975855239e5SApple OSS Distributions 					fiec->produced += counter->u.filter.produced;
976855239e5SApple OSS Distributions 					fiec->checksForWork += counter->u.filter.checksForWork;
977855239e5SApple OSS Distributions 					break;
978855239e5SApple OSS Distributions 				case kIOStatisticsTimerEventSourceCounter:
979855239e5SApple OSS Distributions 					tec->created++;
980855239e5SApple OSS Distributions 					tec->timeouts += counter->u.timer.timeouts;
981855239e5SApple OSS Distributions 					tec->checksForWork += counter->u.timer.checksForWork;
982855239e5SApple OSS Distributions 					tec->timeOnGate += counter->timeOnGate;
983855239e5SApple OSS Distributions 					tec->closeGateCalls += counter->closeGateCalls;
984855239e5SApple OSS Distributions 					tec->openGateCalls += counter->openGateCalls;
985855239e5SApple OSS Distributions 					break;
986855239e5SApple OSS Distributions 				case kIOStatisticsCommandGateCounter:
987855239e5SApple OSS Distributions 					cgc->created++;
988855239e5SApple OSS Distributions 					cgc->timeOnGate += counter->timeOnGate;
989855239e5SApple OSS Distributions 					cgc->actionCalls += counter->u.commandGate.actionCalls;
990855239e5SApple OSS Distributions 					break;
991855239e5SApple OSS Distributions 				case kIOStatisticsCommandQueueCounter:
992855239e5SApple OSS Distributions 					cqc->created++;
993855239e5SApple OSS Distributions 					cqc->actionCalls += counter->u.commandQueue.actionCalls;
994855239e5SApple OSS Distributions 					break;
995855239e5SApple OSS Distributions 				case kIOStatisticsDerivedEventSourceCounter:
996855239e5SApple OSS Distributions 					dec->created++;
997855239e5SApple OSS Distributions 					dec->timeOnGate += counter->timeOnGate;
998855239e5SApple OSS Distributions 					dec->closeGateCalls += counter->closeGateCalls;
999855239e5SApple OSS Distributions 					dec->openGateCalls += counter->openGateCalls;
1000855239e5SApple OSS Distributions 					break;
1001855239e5SApple OSS Distributions 				default:
1002855239e5SApple OSS Distributions 					break;
1003855239e5SApple OSS Distributions 				}
1004855239e5SApple OSS Distributions 			}
1005855239e5SApple OSS Distributions 
1006855239e5SApple OSS Distributions 			stats++;
1007855239e5SApple OSS Distributions 		}
1008855239e5SApple OSS Distributions 	}
1009855239e5SApple OSS Distributions 
1010855239e5SApple OSS Distributions 	return sizeof(IOStatisticsCounter) * registeredClasses;
1011855239e5SApple OSS Distributions }
1012855239e5SApple OSS Distributions 
1013a5e72196SApple OSS Distributions uint32_t
copyKextIdentifiers(IOStatisticsKextIdentifier * kextIDs)1014a5e72196SApple OSS Distributions IOStatistics::copyKextIdentifiers(IOStatisticsKextIdentifier *kextIDs)
1015855239e5SApple OSS Distributions {
1016855239e5SApple OSS Distributions 	KextNode *ke;
1017855239e5SApple OSS Distributions 
1018855239e5SApple OSS Distributions 	RB_FOREACH(ke, KextTree, &kextHead) {
1019855239e5SApple OSS Distributions 		strncpy(kextIDs->identifier, ke->kext->getIdentifierCString(), kIOStatisticsDriverNameLength);
1020855239e5SApple OSS Distributions 		kextIDs++;
1021855239e5SApple OSS Distributions 	}
1022855239e5SApple OSS Distributions 
1023a5e72196SApple OSS Distributions 	return sizeof(IOStatisticsKextIdentifier) * loadedKexts;
1024855239e5SApple OSS Distributions }
1025855239e5SApple OSS Distributions 
1026a5e72196SApple OSS Distributions uint32_t
copyClassNames(IOStatisticsClassName * classNames)1027a5e72196SApple OSS Distributions IOStatistics::copyClassNames(IOStatisticsClassName *classNames)
1028855239e5SApple OSS Distributions {
1029855239e5SApple OSS Distributions 	KextNode *ke;
1030855239e5SApple OSS Distributions 	ClassNode *ce;
1031855239e5SApple OSS Distributions 
1032855239e5SApple OSS Distributions 	RB_FOREACH(ke, KextTree, &kextHead) {
1033855239e5SApple OSS Distributions 		SLIST_FOREACH(ce, &ke->classList, lLink) {
1034855239e5SApple OSS Distributions 			strncpy(classNames->name, ce->metaClass->getClassName(), kIOStatisticsClassNameLength);
1035855239e5SApple OSS Distributions 			classNames++;
1036855239e5SApple OSS Distributions 		}
1037855239e5SApple OSS Distributions 	}
1038855239e5SApple OSS Distributions 
1039a5e72196SApple OSS Distributions 	return sizeof(IOStatisticsClassName) * registeredClasses;
1040855239e5SApple OSS Distributions }
1041855239e5SApple OSS Distributions 
1042a5e72196SApple OSS Distributions uint32_t
copyWorkLoopStatistics(IOStatisticsWorkLoop * stats)1043a5e72196SApple OSS Distributions IOStatistics::copyWorkLoopStatistics(IOStatisticsWorkLoop *stats)
1044855239e5SApple OSS Distributions {
1045855239e5SApple OSS Distributions 	KextNode *ke;
1046855239e5SApple OSS Distributions 	IOWorkLoopCounter *wlc;
1047855239e5SApple OSS Distributions 	IOWorkLoopDependency *dependentNode;
1048855239e5SApple OSS Distributions 	uint32_t size, accumulatedSize = 0;
1049855239e5SApple OSS Distributions 
1050855239e5SApple OSS Distributions 	RB_FOREACH(ke, KextTree, &kextHead) {
1051855239e5SApple OSS Distributions 		SLIST_FOREACH(wlc, &ke->workLoopList, link) {
1052855239e5SApple OSS Distributions 			stats->kextLoadTag = ke->loadTag;
1053855239e5SApple OSS Distributions 			stats->attachedEventSources = wlc->attachedEventSources;
1054855239e5SApple OSS Distributions 			stats->timeOnGate = wlc->timeOnGate;
1055855239e5SApple OSS Distributions 			stats->dependentKexts = 0;
1056855239e5SApple OSS Distributions 			RB_FOREACH(dependentNode, IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead) {
1057855239e5SApple OSS Distributions 				stats->dependentKextLoadTags[stats->dependentKexts] = dependentNode->loadTag;
1058855239e5SApple OSS Distributions 				stats->dependentKexts++;
1059855239e5SApple OSS Distributions 			}
1060855239e5SApple OSS Distributions 
1061855239e5SApple OSS Distributions 			size = sizeof(IOStatisticsWorkLoop) + (sizeof(uint32_t) * stats->dependentKexts);
1062855239e5SApple OSS Distributions 
1063855239e5SApple OSS Distributions 			accumulatedSize += size;
1064855239e5SApple OSS Distributions 			stats = (IOStatisticsWorkLoop*)((void*)((char*)stats + size));
1065855239e5SApple OSS Distributions 		}
1066855239e5SApple OSS Distributions 	}
1067855239e5SApple OSS Distributions 
1068855239e5SApple OSS Distributions 	return accumulatedSize;
1069855239e5SApple OSS Distributions }
1070855239e5SApple OSS Distributions 
1071a5e72196SApple OSS Distributions uint32_t
copyUserClientStatistics(IOStatisticsUserClientHeader * stats,uint32_t loadTag)1072a5e72196SApple OSS Distributions IOStatistics::copyUserClientStatistics(IOStatisticsUserClientHeader *stats, uint32_t loadTag)
1073855239e5SApple OSS Distributions {
1074855239e5SApple OSS Distributions 	KextNode *sought, *found = NULL;
1075855239e5SApple OSS Distributions 	uint32_t procs = 0;
1076855239e5SApple OSS Distributions 	IOUserClientProcessEntry *processEntry;
1077855239e5SApple OSS Distributions 
1078855239e5SApple OSS Distributions 	RB_FOREACH(sought, KextTree, &kextHead) {
1079855239e5SApple OSS Distributions 		if (sought->loadTag == loadTag) {
1080855239e5SApple OSS Distributions 			found = sought;
1081855239e5SApple OSS Distributions 			break;
1082855239e5SApple OSS Distributions 		}
1083855239e5SApple OSS Distributions 	}
1084855239e5SApple OSS Distributions 
1085855239e5SApple OSS Distributions 	if (!found) {
1086855239e5SApple OSS Distributions 		return 0;
1087855239e5SApple OSS Distributions 	}
1088855239e5SApple OSS Distributions 
1089855239e5SApple OSS Distributions 	TAILQ_FOREACH(processEntry, &found->userClientCallList, link) {
1090855239e5SApple OSS Distributions 		strncpy(stats->userClientCalls[procs].processName, processEntry->processName, kIOStatisticsProcessNameLength);
1091855239e5SApple OSS Distributions 		stats->userClientCalls[procs].pid = processEntry->pid;
1092855239e5SApple OSS Distributions 		stats->userClientCalls[procs].calls = processEntry->calls;
1093855239e5SApple OSS Distributions 		stats->processes++;
1094855239e5SApple OSS Distributions 		procs++;
1095855239e5SApple OSS Distributions 	}
1096855239e5SApple OSS Distributions 
1097855239e5SApple OSS Distributions 	return sizeof(IOStatisticsUserClientCall) * stats->processes;
1098855239e5SApple OSS Distributions }
1099855239e5SApple OSS Distributions 
1100a5e72196SApple OSS Distributions void
storeUserClientCallInfo(IOUserClient * userClient,IOUserClientCounter * counter)1101a5e72196SApple OSS Distributions IOStatistics::storeUserClientCallInfo(IOUserClient *userClient, IOUserClientCounter *counter)
1102855239e5SApple OSS Distributions {
1103855239e5SApple OSS Distributions 	OSString *ossUserClientCreator = NULL;
1104855239e5SApple OSS Distributions 	int32_t pid = -1;
1105855239e5SApple OSS Distributions 	KextNode *parentKext;
1106855239e5SApple OSS Distributions 	IOUserClientProcessEntry *entry, *nextEntry, *prevEntry = NULL;
1107855239e5SApple OSS Distributions 	uint32_t count = 0;
1108855239e5SApple OSS Distributions 	const char *ptr = NULL;
1109855239e5SApple OSS Distributions 	OSObject *obj;
1110855239e5SApple OSS Distributions 
1111855239e5SApple OSS Distributions 	/* TODO: see if this can be more efficient */
1112855239e5SApple OSS Distributions 	obj = userClient->copyProperty("IOUserClientCreator",
1113855239e5SApple OSS Distributions 	    gIOServicePlane,
1114855239e5SApple OSS Distributions 	    kIORegistryIterateRecursively | kIORegistryIterateParents);
1115855239e5SApple OSS Distributions 
1116a5e72196SApple OSS Distributions 	if (!obj) {
1117855239e5SApple OSS Distributions 		goto err_nounlock;
1118a5e72196SApple OSS Distributions 	}
1119855239e5SApple OSS Distributions 
1120855239e5SApple OSS Distributions 	ossUserClientCreator = OSDynamicCast(OSString, obj);
1121855239e5SApple OSS Distributions 
1122855239e5SApple OSS Distributions 	if (ossUserClientCreator) {
1123855239e5SApple OSS Distributions 		uint32_t len, lenIter = 0;
1124855239e5SApple OSS Distributions 
1125855239e5SApple OSS Distributions 		ptr = ossUserClientCreator->getCStringNoCopy();
1126855239e5SApple OSS Distributions 		len = ossUserClientCreator->getLength();
1127855239e5SApple OSS Distributions 
1128855239e5SApple OSS Distributions 		while ((*ptr != ' ') && (lenIter < len)) {
1129855239e5SApple OSS Distributions 			ptr++;
1130855239e5SApple OSS Distributions 			lenIter++;
1131855239e5SApple OSS Distributions 		}
1132855239e5SApple OSS Distributions 
1133855239e5SApple OSS Distributions 		if (lenIter < len) {
1134855239e5SApple OSS Distributions 			ptr++; // Skip the space
1135855239e5SApple OSS Distributions 			lenIter++;
1136855239e5SApple OSS Distributions 			pid = 0;
1137855239e5SApple OSS Distributions 			while ((*ptr != ',') && (lenIter < len)) {
1138855239e5SApple OSS Distributions 				pid = pid * 10 + (*ptr - '0');
1139855239e5SApple OSS Distributions 				ptr++;
1140855239e5SApple OSS Distributions 				lenIter++;
1141855239e5SApple OSS Distributions 			}
1142855239e5SApple OSS Distributions 
1143855239e5SApple OSS Distributions 			if (lenIter == len) {
1144855239e5SApple OSS Distributions 				pid = -1;
1145855239e5SApple OSS Distributions 			} else {
1146855239e5SApple OSS Distributions 				ptr += 2;
1147855239e5SApple OSS Distributions 			}
1148855239e5SApple OSS Distributions 		}
1149855239e5SApple OSS Distributions 	}
1150855239e5SApple OSS Distributions 
1151a5e72196SApple OSS Distributions 	if (-1 == pid) {
1152855239e5SApple OSS Distributions 		goto err_nounlock;
1153a5e72196SApple OSS Distributions 	}
1154855239e5SApple OSS Distributions 
1155855239e5SApple OSS Distributions 	IORWLockWrite(lock);
1156855239e5SApple OSS Distributions 
1157855239e5SApple OSS Distributions 	parentKext = counter->parentClass->parentKext;
1158855239e5SApple OSS Distributions 
1159855239e5SApple OSS Distributions 	TAILQ_FOREACH(entry, &parentKext->userClientCallList, link) {
1160855239e5SApple OSS Distributions 		if (entry->pid == pid) {
1161855239e5SApple OSS Distributions 			/* Found, so increment count and move to the head */
1162855239e5SApple OSS Distributions 			entry->calls++;
1163855239e5SApple OSS Distributions 			if (count) {
1164855239e5SApple OSS Distributions 				TAILQ_REMOVE(&parentKext->userClientCallList, entry, link);
1165855239e5SApple OSS Distributions 				break;
1166a5e72196SApple OSS Distributions 			} else {
1167855239e5SApple OSS Distributions 				/* At the head already, so increment and return */
1168855239e5SApple OSS Distributions 				goto err_unlock;
1169855239e5SApple OSS Distributions 			}
1170855239e5SApple OSS Distributions 		}
1171855239e5SApple OSS Distributions 
1172855239e5SApple OSS Distributions 		count++;
1173855239e5SApple OSS Distributions 	}
1174855239e5SApple OSS Distributions 
1175855239e5SApple OSS Distributions 	if (!entry) {
1176855239e5SApple OSS Distributions 		if (count == IOKIT_STATISTICS_RECORDED_USERCLIENT_PROCS) {
1177855239e5SApple OSS Distributions 			/* Max elements hit, so reuse the last */
1178855239e5SApple OSS Distributions 			entry = TAILQ_LAST(&parentKext->userClientCallList, ProcessEntryList);
1179855239e5SApple OSS Distributions 			TAILQ_REMOVE(&parentKext->userClientCallList, entry, link);
1180a5e72196SApple OSS Distributions 		} else {
1181855239e5SApple OSS Distributions 			/* Otherwise, allocate a new entry */
1182*e6231be0SApple OSS Distributions 			entry = kalloc_type(IOUserClientProcessEntry, Z_WAITOK);
1183855239e5SApple OSS Distributions 			if (!entry) {
1184*e6231be0SApple OSS Distributions 				goto err_unlock;
1185855239e5SApple OSS Distributions 			}
1186855239e5SApple OSS Distributions 		}
1187855239e5SApple OSS Distributions 
1188855239e5SApple OSS Distributions 		strncpy(entry->processName, ptr, kIOStatisticsProcessNameLength);
1189855239e5SApple OSS Distributions 		entry->pid = pid;
1190855239e5SApple OSS Distributions 		entry->calls = 1;
1191855239e5SApple OSS Distributions 	}
1192855239e5SApple OSS Distributions 
1193855239e5SApple OSS Distributions 	TAILQ_FOREACH(nextEntry, &parentKext->userClientCallList, link) {
1194a5e72196SApple OSS Distributions 		if (nextEntry->calls <= entry->calls) {
1195855239e5SApple OSS Distributions 			break;
1196a5e72196SApple OSS Distributions 		}
1197855239e5SApple OSS Distributions 
1198855239e5SApple OSS Distributions 		prevEntry = nextEntry;
1199855239e5SApple OSS Distributions 	}
1200855239e5SApple OSS Distributions 
1201a5e72196SApple OSS Distributions 	if (!prevEntry) {
1202855239e5SApple OSS Distributions 		TAILQ_INSERT_HEAD(&parentKext->userClientCallList, entry, link);
1203a5e72196SApple OSS Distributions 	} else {
1204855239e5SApple OSS Distributions 		TAILQ_INSERT_AFTER(&parentKext->userClientCallList, prevEntry, entry, link);
1205a5e72196SApple OSS Distributions 	}
1206855239e5SApple OSS Distributions 
1207855239e5SApple OSS Distributions err_unlock:
1208855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
1209855239e5SApple OSS Distributions 
1210855239e5SApple OSS Distributions err_nounlock:
1211a5e72196SApple OSS Distributions 	if (obj) {
1212855239e5SApple OSS Distributions 		obj->release();
1213855239e5SApple OSS Distributions 	}
1214a5e72196SApple OSS Distributions }
1215855239e5SApple OSS Distributions 
1216a5e72196SApple OSS Distributions void
countUserClientCall(IOUserClient * client)1217a5e72196SApple OSS Distributions IOStatistics::countUserClientCall(IOUserClient *client)
1218a5e72196SApple OSS Distributions {
1219855239e5SApple OSS Distributions 	IOUserClient::ExpansionData *data;
1220855239e5SApple OSS Distributions 	IOUserClientCounter *counter;
1221855239e5SApple OSS Distributions 
1222855239e5SApple OSS Distributions 	/* Guard against an uninitialized client object - <rdar://problem/8577946> */
1223855239e5SApple OSS Distributions 	if (!(data = client->reserved)) {
1224855239e5SApple OSS Distributions 		return;
1225855239e5SApple OSS Distributions 	}
1226855239e5SApple OSS Distributions 
1227855239e5SApple OSS Distributions 	if ((counter = data->counter)) {
1228855239e5SApple OSS Distributions 		storeUserClientCallInfo(client, counter);
1229855239e5SApple OSS Distributions 		OSIncrementAtomic(&counter->clientCalls);
1230855239e5SApple OSS Distributions 	}
1231855239e5SApple OSS Distributions }
1232855239e5SApple OSS Distributions 
1233a5e72196SApple OSS Distributions KextNode *
getKextNodeFromBacktrace(boolean_t write)1234a5e72196SApple OSS Distributions IOStatistics::getKextNodeFromBacktrace(boolean_t write)
1235a5e72196SApple OSS Distributions {
1236855239e5SApple OSS Distributions 	const uint32_t btMin = 3;
1237855239e5SApple OSS Distributions 
1238855239e5SApple OSS Distributions 	void *bt[16];
1239855239e5SApple OSS Distributions 	unsigned btCount = sizeof(bt) / sizeof(bt[0]);
1240855239e5SApple OSS Distributions 	vm_offset_t *scanAddr = NULL;
1241855239e5SApple OSS Distributions 	uint32_t i;
1242855239e5SApple OSS Distributions 	KextNode *found = NULL, *ke = NULL;
1243855239e5SApple OSS Distributions 
1244186b8fceSApple OSS Distributions 	/*
1245186b8fceSApple OSS Distributions 	 * Gathering the backtrace is a significant source of
1246186b8fceSApple OSS Distributions 	 * overhead. OSBacktrace does many safety checks that
1247186b8fceSApple OSS Distributions 	 * are not needed in this situation.
1248186b8fceSApple OSS Distributions 	 */
1249*e6231be0SApple OSS Distributions 	btCount = backtrace((uintptr_t*)bt, btCount, NULL, NULL);
1250855239e5SApple OSS Distributions 
1251855239e5SApple OSS Distributions 	if (write) {
1252855239e5SApple OSS Distributions 		IORWLockWrite(lock);
1253855239e5SApple OSS Distributions 	} else {
1254855239e5SApple OSS Distributions 		IORWLockRead(lock);
1255855239e5SApple OSS Distributions 	}
1256855239e5SApple OSS Distributions 
1257855239e5SApple OSS Distributions 	/* Ignore first levels */
1258855239e5SApple OSS Distributions 	scanAddr = (vm_offset_t *)&bt[btMin - 1];
1259855239e5SApple OSS Distributions 
1260d0c1fef6SApple OSS Distributions 	for (i = btMin - 1; i < btCount; i++, scanAddr++) {
1261855239e5SApple OSS Distributions 		ke = RB_ROOT(&kextAddressHead);
1262855239e5SApple OSS Distributions 		while (ke) {
1263855239e5SApple OSS Distributions 			if (*scanAddr < ke->address) {
1264855239e5SApple OSS Distributions 				ke = RB_LEFT(ke, addressLink);
1265a5e72196SApple OSS Distributions 			} else {
1266855239e5SApple OSS Distributions 				if ((*scanAddr < ke->address_end) && (*scanAddr >= ke->address)) {
1267855239e5SApple OSS Distributions 					if (!ke->kext->isKernelComponent()) {
1268855239e5SApple OSS Distributions 						return ke;
1269855239e5SApple OSS Distributions 					} else {
1270855239e5SApple OSS Distributions 						found = ke;
1271855239e5SApple OSS Distributions 					}
1272855239e5SApple OSS Distributions 				}
1273855239e5SApple OSS Distributions 				ke = RB_RIGHT(ke, addressLink);
1274855239e5SApple OSS Distributions 			}
1275855239e5SApple OSS Distributions 		}
1276855239e5SApple OSS Distributions 	}
1277855239e5SApple OSS Distributions 
1278855239e5SApple OSS Distributions 	if (!found) {
1279855239e5SApple OSS Distributions 		IORWLockUnlock(lock);
1280855239e5SApple OSS Distributions 	}
1281855239e5SApple OSS Distributions 
1282855239e5SApple OSS Distributions 	return found;
1283855239e5SApple OSS Distributions }
1284855239e5SApple OSS Distributions 
1285a5e72196SApple OSS Distributions void
releaseKextNode(KextNode * node)1286a5e72196SApple OSS Distributions IOStatistics::releaseKextNode(KextNode *node)
1287a5e72196SApple OSS Distributions {
1288855239e5SApple OSS Distributions #pragma unused(node)
1289855239e5SApple OSS Distributions 	IORWLockUnlock(lock);
1290855239e5SApple OSS Distributions }
1291855239e5SApple OSS Distributions 
1292855239e5SApple OSS Distributions /* IOLib allocations */
1293a5e72196SApple OSS Distributions void
countAlloc(uint32_t index,vm_size_t size)1294a5e72196SApple OSS Distributions IOStatistics::countAlloc(uint32_t index, vm_size_t size)
1295a5e72196SApple OSS Distributions {
1296855239e5SApple OSS Distributions 	KextNode *ke;
1297855239e5SApple OSS Distributions 
1298855239e5SApple OSS Distributions 	if (!enabled) {
1299855239e5SApple OSS Distributions 		return;
1300855239e5SApple OSS Distributions 	}
1301bb611c8fSApple OSS Distributions 	if (size > INT_MAX) {
1302bb611c8fSApple OSS Distributions 		return;
1303bb611c8fSApple OSS Distributions 	}
1304855239e5SApple OSS Distributions 
1305855239e5SApple OSS Distributions 	ke = getKextNodeFromBacktrace(FALSE);
1306855239e5SApple OSS Distributions 	if (ke) {
1307bb611c8fSApple OSS Distributions 		OSAddAtomic((SInt32) size, &ke->memoryCounters[index]);
1308855239e5SApple OSS Distributions 		releaseKextNode(ke);
1309855239e5SApple OSS Distributions 	}
1310855239e5SApple OSS Distributions }
1311855239e5SApple OSS Distributions 
1312855239e5SApple OSS Distributions #endif /* IOKITSTATS */
1313