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