]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOReporter.cpp
xnu-7195.60.75.tar.gz
[apple/xnu.git] / iokit / Kernel / IOReporter.cpp
CommitLineData
fe8ab488
A
1/*
2 * Copyright (c) 2012-2013 Apple Computer, Inc. All Rights Reserved.
0a7de745 3 *
fe8ab488 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
fe8ab488
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
fe8ab488
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
fe8ab488
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
fe8ab488
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
f427ee49
A
29#define IOKIT_ENABLE_SHARED_PTR
30
fe8ab488
A
31#include <IOKit/IOKernelReportStructs.h>
32#include <IOKit/IOKernelReporters.h>
33#include "IOReporterDefs.h"
34
35#include <string.h>
36#include <IOKit/IORegistryEntry.h>
37
38#define super OSObject
39OSDefineMetaClassAndStructors(IOReporter, OSObject);
40
f427ee49 41static OSSharedPtr<const OSSymbol> gIOReportNoChannelName;
fe8ab488
A
42
43// * We might someday want an IOReportManager (vs. these static funcs)
44
45/**************************************/
46/*** STATIC METHODS ***/
47/**************************************/
48IOReturn
49IOReporter::configureAllReports(OSSet *reporters,
0a7de745
A
50 IOReportChannelList *channelList,
51 IOReportConfigureAction action,
52 void *result,
53 void *destination)
fe8ab488 54{
0a7de745 55 IOReturn rval = kIOReturnError;
f427ee49 56 OSSharedPtr<OSCollectionIterator> iterator;
0a7de745
A
57
58 if (reporters == NULL || channelList == NULL || result == NULL) {
59 rval = kIOReturnBadArgument;
60 goto finish;
61 }
62
63 switch (action) {
64 case kIOReportGetDimensions:
65 case kIOReportEnable:
66 case kIOReportDisable:
67 {
68 OSObject * object;
69 iterator = OSCollectionIterator::withCollection(reporters);
70
71 while ((object = iterator->getNextObject())) {
72 IOReporter *rep = OSDynamicCast(IOReporter, object);
73
74 if (rep) {
75 (void)rep->configureReport(channelList, action, result, destination);
76 } else {
77 rval = kIOReturnUnsupported; // kIOReturnNotFound?
78 goto finish;
79 }
80 }
81
82 break;
83 }
84
85 case kIOReportTraceOnChange:
86 case kIOReportNotifyHubOnChange:
87 default:
88 rval = kIOReturnUnsupported;
89 goto finish;
90 }
91
92 rval = kIOReturnSuccess;
93
fe8ab488 94finish:
0a7de745 95 return rval;
fe8ab488
A
96}
97
98// the duplication in these functions almost makes one want Objective-C SEL* ;)
99IOReturn
100IOReporter::updateAllReports(OSSet *reporters,
0a7de745
A
101 IOReportChannelList *channelList,
102 IOReportConfigureAction action,
103 void *result,
104 void *destination)
fe8ab488 105{
0a7de745 106 IOReturn rval = kIOReturnError;
f427ee49 107 OSSharedPtr<OSCollectionIterator> iterator;
0a7de745
A
108
109 if (reporters == NULL ||
110 channelList == NULL ||
111 result == NULL ||
112 destination == NULL) {
113 rval = kIOReturnBadArgument;
114 goto finish;
115 }
116
117 switch (action) {
118 case kIOReportCopyChannelData:
119 {
120 OSObject * object;
121 iterator = OSCollectionIterator::withCollection(reporters);
122
123 while ((object = iterator->getNextObject())) {
124 IOReporter *rep = OSDynamicCast(IOReporter, object);
125
126 if (rep) {
127 (void)rep->updateReport(channelList, action, result, destination);
128 } else {
129 rval = kIOReturnUnsupported; // kIOReturnNotFound?
130 goto finish;
131 }
132 }
133
134 break;
135 }
136
137 case kIOReportTraceChannelData:
138 default:
139 rval = kIOReturnUnsupported;
140 goto finish;
141 }
142
143 rval = kIOReturnSuccess;
fe8ab488
A
144
145finish:
0a7de745 146 return rval;
fe8ab488
A
147}
148
149
150/**************************************/
151/*** COMMON INIT METHODS ***/
152/**************************************/
153
154bool
155IOReporter::init(IOService *reportingService,
0a7de745
A
156 IOReportChannelType channelType,
157 IOReportUnit unit)
fe8ab488 158{
0a7de745
A
159 bool success = false;
160
161 // ::free() relies on these being initialized
162 _reporterLock = NULL;
163 _configLock = NULL;
164 _elements = NULL;
165 _enableCounts = NULL;
f427ee49 166 _channelNames = nullptr;
0a7de745
A
167
168 if (channelType.report_format == kIOReportInvalidFormat) {
169 IORLOG("init ERROR: Channel Type ill-defined");
170 goto finish;
171 }
172
173 _driver_id = reportingService->getRegistryEntryID();
174 if (_driver_id == 0) {
175 IORLOG("init() ERROR: no registry ID");
176 goto finish;
177 }
178
179 if (!super::init()) {
180 return false;
181 }
182
f427ee49
A
183 if (channelType.nelements > INT16_MAX) {
184 return false;
185 }
0a7de745
A
186 _channelDimension = channelType.nelements;
187 _channelType = channelType;
188 // FIXME: need to look up dynamically
189 if (unit == kIOReportUnitHWTicks) {
5ba3f43e 190#if defined(__arm__) || defined(__arm64__)
0a7de745 191 unit = kIOReportUnit24MHzTicks;
5ba3f43e 192#elif defined(__i386__) || defined(__x86_64__)
0a7de745
A
193 // Most, but not all Macs use 1GHz
194 unit = kIOReportUnit1GHzTicks;
fe8ab488
A
195#else
196#error kIOReportUnitHWTicks not defined
197#endif
0a7de745
A
198 }
199 _unit = unit;
200
201 // Allocate a reporter (data) lock
202 _reporterLock = IOSimpleLockAlloc();
203 if (!_reporterLock) {
204 goto finish;
205 }
206 _reporterIsLocked = false;
207
208 // Allocate a config lock
209 _configLock = IOLockAlloc();
210 if (!_configLock) {
211 goto finish;
212 }
213 _reporterConfigIsLocked = false;
214
215 // Allocate channel names array
216 _channelNames = OSArray::withCapacity(1);
217 if (!_channelNames) {
218 goto finish;
219 }
220
221 // success
222 success = true;
fe8ab488
A
223
224finish:
0a7de745 225 return success;
fe8ab488
A
226}
227
228
229/*******************************/
230/*** PUBLIC METHODS ***/
231/*******************************/
232
f427ee49
A
233void
234IOReporter::initialize(void)
235{
236 gIOReportNoChannelName = OSSymbol::withCString("_NO_NAME_4");
237}
238
fe8ab488
A
239// init() [possibly via init*()] must be called before free()
240// to ensure that _<var> = NULL
241void
242IOReporter::free(void)
0a7de745 243{
0a7de745
A
244 if (_configLock) {
245 IOLockFree(_configLock);
246 }
247 if (_reporterLock) {
248 IOSimpleLockFree(_reporterLock);
249 }
250
251 if (_elements) {
252 PREFL_MEMOP_PANIC(_nElements, IOReportElement);
253 IOFree(_elements, (size_t)_nElements * sizeof(IOReportElement));
254 }
255 if (_enableCounts) {
256 PREFL_MEMOP_PANIC(_nChannels, int);
257 IOFree(_enableCounts, (size_t)_nChannels * sizeof(int));
258 }
259
260 super::free();
fe8ab488
A
261}
262
263/*
0a7de745
A
264 #define TESTALLOC() do { \
265 * void *tbuf; \
266 * tbuf = IOMalloc(10); \
267 * IOFree(tbuf, 10); \
268 * IORLOG("%s:%d - _reporterIsLocked = %d & allocation successful", \
269 * __PRETTY_FUNCTION__, __LINE__, _reporterIsLocked); \
270 * } while (0);
271 */
fe8ab488
A
272IOReturn
273IOReporter::addChannel(uint64_t channelID,
0a7de745 274 const char *channelName /* = NULL */)
fe8ab488 275{
0a7de745 276 IOReturn res = kIOReturnError, kerr;
f427ee49 277 OSSharedPtr<const OSSymbol> symChannelName;
0a7de745
A
278 int oldNChannels, newNChannels = 0, freeNChannels = 0;
279
280 IORLOG("IOReporter::addChannel %llx", channelID);
281
282 // protect instance variables (but not contents)
283 lockReporterConfig();
284
285 // FIXME: Check if any channel is already present and return error
286
287 // addChannel() always adds one channel
288 oldNChannels = _nChannels;
289 if (oldNChannels < 0 || oldNChannels > INT_MAX - 1) {
290 res = kIOReturnOverrun;
291 goto finish;
292 }
293 newNChannels = oldNChannels + 1;
294 freeNChannels = newNChannels; // until swap success
295
296 // Expand addChannel()-specific data structure
297 if (_channelNames->ensureCapacity((unsigned)newNChannels) <
298 (unsigned)newNChannels) {
299 res = kIOReturnNoMemory; goto finish;
300 }
301 if (channelName) {
302 symChannelName = OSSymbol::withCString(channelName);
303 if (!symChannelName) {
304 res = kIOReturnNoMemory; goto finish;
305 }
306 } else {
307 // grab a reference to our shared global
308 symChannelName = gIOReportNoChannelName;
0a7de745
A
309 }
310
311 // allocate new buffers into _swap* variables
312 if ((kerr = handleSwapPrepare(newNChannels))) {
313 // on error, channels are *not* swapped
314 res = kerr; goto finish;
315 }
316
317 // exchange main and _swap* buffers with buffer contents protected
318 // IOReporter::handleAddChannelSwap() also increments _nElements, etc
319 lockReporter();
f427ee49 320 res = handleAddChannelSwap(channelID, symChannelName.get());
0a7de745
A
321 unlockReporter();
322 // On failure, handleAddChannelSwap() leaves *new* buffers in _swap*.
323 // On success, it's the old buffers, so we put the right size in here.
324 if (res == kIOReturnSuccess) {
325 freeNChannels = oldNChannels;
326 }
fe8ab488
A
327
328finish:
0a7de745
A
329 // free up not-in-use buffers (tracked by _swap*)
330 handleSwapCleanup(freeNChannels);
f427ee49 331
0a7de745
A
332 unlockReporterConfig();
333
334 return res;
fe8ab488
A
335}
336
337
f427ee49 338OSSharedPtr<IOReportLegendEntry>
fe8ab488
A
339IOReporter::createLegend(void)
340{
f427ee49 341 OSSharedPtr<IOReportLegendEntry> legendEntry;
0a7de745
A
342
343 lockReporterConfig();
344
345 legendEntry = handleCreateLegend();
346
347 unlockReporterConfig();
348
349 return legendEntry;
fe8ab488
A
350}
351
352
353IOReturn
354IOReporter::configureReport(IOReportChannelList *channelList,
0a7de745
A
355 IOReportConfigureAction action,
356 void *result,
357 void *destination)
fe8ab488 358{
0a7de745
A
359 IOReturn res = kIOReturnError;
360
361 lockReporterConfig();
362
363 res = handleConfigureReport(channelList, action, result, destination);
364
365 unlockReporterConfig();
366
367 return res;
fe8ab488
A
368}
369
370
371IOReturn
372IOReporter::updateReport(IOReportChannelList *channelList,
0a7de745
A
373 IOReportConfigureAction action,
374 void *result,
375 void *destination)
fe8ab488 376{
0a7de745
A
377 IOReturn res = kIOReturnError;
378
379 lockReporter();
380
381 res = handleUpdateReport(channelList, action, result, destination);
382
383 unlockReporter();
384
385 return res;
fe8ab488
A
386}
387
388
389/*******************************/
390/*** PROTECTED METHODS ***/
391/*******************************/
392
393
394void
395IOReporter::lockReporter()
396{
0a7de745
A
397 _interruptState = IOSimpleLockLockDisableInterrupt(_reporterLock);
398 _reporterIsLocked = true;
fe8ab488
A
399}
400
401
402void
403IOReporter::unlockReporter()
404{
0a7de745
A
405 _reporterIsLocked = false;
406 IOSimpleLockUnlockEnableInterrupt(_reporterLock, _interruptState);
fe8ab488
A
407}
408
409void
410IOReporter::lockReporterConfig()
411{
0a7de745
A
412 IOLockLock(_configLock);
413 _reporterConfigIsLocked = true;
fe8ab488
A
414}
415
416void
417IOReporter::unlockReporterConfig()
418{
0a7de745
A
419 _reporterConfigIsLocked = false;
420 IOLockUnlock(_configLock);
fe8ab488
A
421}
422
423
424IOReturn
425IOReporter::handleSwapPrepare(int newNChannels)
426{
0a7de745
A
427 IOReturn res = kIOReturnError;
428 int newNElements;
429 size_t newElementsSize, newECSize;
430
431 // analyzer appeasement
432 newElementsSize = newECSize = 0;
433
434 //IORLOG("IOReporter::handleSwapPrepare");
435
436 IOREPORTER_CHECK_CONFIG_LOCK();
437
438 if (newNChannels < _nChannels) {
439 panic("%s doesn't support shrinking", __func__);
440 }
441 if (newNChannels <= 0 || _channelDimension <= 0) {
442 res = kIOReturnUnderrun;
443 goto finish;
444 }
445 if (_swapElements || _swapEnableCounts) {
446 panic("IOReporter::_swap* already in use");
447 }
448
449 // calculate the number of elements given #ch & the dimension of each
450 if (newNChannels < 0 || newNChannels > INT_MAX / _channelDimension) {
451 res = kIOReturnOverrun;
452 goto finish;
453 }
454 newNElements = newNChannels * _channelDimension;
455
456 // Allocate memory for the new array of report elements
457 PREFL_MEMOP_FAIL(newNElements, IOReportElement);
458 newElementsSize = (size_t)newNElements * sizeof(IOReportElement);
459 _swapElements = (IOReportElement *)IOMalloc(newElementsSize);
460 if (_swapElements == NULL) {
461 res = kIOReturnNoMemory; goto finish;
462 }
463 memset(_swapElements, 0, newElementsSize);
464
465 // Allocate memory for the new array of channel watch counts
466 PREFL_MEMOP_FAIL(newNChannels, int);
467 newECSize = (size_t)newNChannels * sizeof(int);
468 _swapEnableCounts = (int *)IOMalloc(newECSize);
469 if (_swapEnableCounts == NULL) {
470 res = kIOReturnNoMemory; goto finish;
471 }
472 memset(_swapEnableCounts, 0, newECSize);
473
474 // success
475 res = kIOReturnSuccess;
fe8ab488
A
476
477finish:
0a7de745
A
478 if (res) {
479 if (_swapElements) {
480 IOFree(_swapElements, newElementsSize);
481 _swapElements = NULL;
482 }
483 if (_swapEnableCounts) {
484 IOFree(_swapEnableCounts, newECSize);
485 _swapEnableCounts = NULL;
486 }
487 }
488
489 return res;
fe8ab488
A
490}
491
492
493IOReturn
494IOReporter::handleAddChannelSwap(uint64_t channel_id,
0a7de745 495 const OSSymbol *symChannelName)
fe8ab488 496{
0a7de745
A
497 IOReturn res = kIOReturnError;
498 int cnt;
499 int *tmpWatchCounts = NULL;
500 IOReportElement *tmpElements = NULL;
501 bool swapComplete = false;
502
503 //IORLOG("IOReporter::handleSwap");
504
505 IOREPORTER_CHECK_CONFIG_LOCK();
506 IOREPORTER_CHECK_LOCK();
507
508 if (!_swapElements || !_swapEnableCounts) {
509 IORLOG("IOReporter::handleSwap ERROR swap variables uninitialized!");
510 goto finish;
511 }
512
513 // Copy any existing elements to the new location
514 //IORLOG("handleSwap (base) -> copying %u elements over...", _nChannels);
515 if (_elements) {
516 PREFL_MEMOP_PANIC(_nElements, IOReportElement);
517 memcpy(_swapElements, _elements,
518 (size_t)_nElements * sizeof(IOReportElement));
519
520 PREFL_MEMOP_PANIC(_nElements, int);
521 memcpy(_swapEnableCounts, _enableCounts,
522 (size_t)_nChannels * sizeof(int));
523 }
524
525 // Update principal instance variables, keep old buffers for cleanup
526 tmpElements = _elements;
527 _elements = _swapElements;
528 _swapElements = tmpElements;
529
530 tmpWatchCounts = _enableCounts;
531 _enableCounts = _swapEnableCounts;
532 _swapEnableCounts = tmpWatchCounts;
533
534 swapComplete = true;
535
536 // but _nChannels & _nElements is still the old (one smaller) size
537
538 // Initialize new element metadata (existing elements copied above)
539 for (cnt = 0; cnt < _channelDimension; cnt++) {
540 _elements[_nElements + cnt].channel_id = channel_id;
541 _elements[_nElements + cnt].provider_id = _driver_id;
542 _elements[_nElements + cnt].channel_type = _channelType;
f427ee49 543 _elements[_nElements + cnt].channel_type.element_idx = ((int16_t) cnt);
0a7de745
A
544
545 //IOREPORTER_DEBUG_ELEMENT(_swapNElements + cnt);
546 }
547
548 // Store a channel name at the end
549 if (!_channelNames->setObject((unsigned)_nChannels, symChannelName)) {
550 // Should never happen because we ensured capacity in addChannel()
551 res = kIOReturnNoMemory;
552 goto finish;
553 }
554
555 // And update the metadata: addChannel() always adds just one channel
556 _nChannels += 1;
557 _nElements += _channelDimension;
558
559 // success
560 res = kIOReturnSuccess;
fe8ab488
A
561
562finish:
0a7de745
A
563 if (res && swapComplete) {
564 // unswap so new buffers get cleaned up instead of old
565 tmpElements = _elements;
566 _elements = _swapElements;
567 _swapElements = tmpElements;
568
569 tmpWatchCounts = _enableCounts;
570 _enableCounts = _swapEnableCounts;
571 _swapEnableCounts = tmpWatchCounts;
572 }
573 return res;
fe8ab488
A
574}
575
576void
577IOReporter::handleSwapCleanup(int swapNChannels)
578{
0a7de745
A
579 int swapNElements;
580
581 if (!_channelDimension || swapNChannels > INT_MAX / _channelDimension) {
582 panic("%s - can't free %d channels of dimension %d", __func__,
583 swapNChannels, _channelDimension);
584 }
585 swapNElements = swapNChannels * _channelDimension;
586
587 IOREPORTER_CHECK_CONFIG_LOCK();
588
589 // release buffers no longer used after swapping
590 if (_swapElements) {
591 PREFL_MEMOP_PANIC(swapNElements, IOReportElement);
592 IOFree(_swapElements, (size_t)swapNElements * sizeof(IOReportElement));
593 _swapElements = NULL;
594 }
595 if (_swapEnableCounts) {
596 PREFL_MEMOP_PANIC(swapNChannels, int);
597 IOFree(_swapEnableCounts, (size_t)swapNChannels * sizeof(int));
598 _swapEnableCounts = NULL;
599 }
fe8ab488
A
600}
601
602
603// The reporter wants to know if its channels have observers.
604// Eventually we'll add some sort of bool ::anyChannelsInUse() which
605// clients can use to cull unused reporters after configureReport(disable).
606IOReturn
607IOReporter::handleConfigureReport(IOReportChannelList *channelList,
0a7de745
A
608 IOReportConfigureAction action,
609 void *result,
610 void *destination)
fe8ab488 611{
0a7de745
A
612 IOReturn res = kIOReturnError;
613 int channel_index = 0;
614 uint32_t chIdx;
615 int *nElements, *nChannels;
616
617 // Check on channelList and result because used below
618 if (!channelList || !result) {
619 goto finish;
620 }
621
622 //IORLOG("IOReporter::configureReport action %u for %u channels",
623 // action, channelList->nchannels);
624
625 // Make sure channel is present, increase matching watch count, 'result'
626 for (chIdx = 0; chIdx < channelList->nchannels; chIdx++) {
627 if (getChannelIndex(channelList->channels[chIdx].channel_id,
628 &channel_index) == kIOReturnSuccess) {
629 // IORLOG("reporter %p recognizes channel %lld", this, channelList->channels[chIdx].channel_id);
630
631 switch (action) {
632 case kIOReportEnable:
633 nChannels = (int*)result;
634 _enabled++;
635 _enableCounts[channel_index]++;
636 (*nChannels)++;
637 break;
638
639 case kIOReportDisable:
640 nChannels = (int*)result;
641 _enabled--;
642 _enableCounts[channel_index]--;
643 (*nChannels)++;
644 break;
645
646 case kIOReportGetDimensions:
647 nElements = (int *)result;
648 *nElements += _channelDimension;
649 break;
650
651 default:
652 IORLOG("ERROR configureReport unknown action!");
653 break;
654 }
655 }
656 }
657
658 // success
659 res = kIOReturnSuccess;
660
fe8ab488 661finish:
0a7de745 662 return res;
fe8ab488
A
663}
664
665
666IOReturn
667IOReporter::handleUpdateReport(IOReportChannelList *channelList,
0a7de745
A
668 IOReportConfigureAction action,
669 void *result,
670 void *destination)
fe8ab488 671{
0a7de745
A
672 IOReturn res = kIOReturnError;
673 int *nElements = (int *)result;
674 int channel_index = 0;
675 uint32_t chIdx;
676 IOBufferMemoryDescriptor *dest;
677
678 if (!channelList || !result || !destination) {
679 goto finish;
680 }
681
682 dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
683 if (dest == NULL) {
684 // Invalid destination
685 res = kIOReturnBadArgument;
686 goto finish;
687 }
688
689 if (!_enabled) {
690 goto finish;
691 }
692
693 for (chIdx = 0; chIdx < channelList->nchannels; chIdx++) {
694 if (getChannelIndex(channelList->channels[chIdx].channel_id,
695 &channel_index) == kIOReturnSuccess) {
696 //IORLOG("%s - found channel_id %llx @ index %d", __func__,
697 // channelList->channels[chIdx].channel_id,
698 // channel_index);
699
700 switch (action) {
701 case kIOReportCopyChannelData:
702 res = updateChannelValues(channel_index);
703 if (res) {
704 IORLOG("ERROR: updateChannelValues() failed: %x", res);
705 goto finish;
706 }
707
708 res = updateReportChannel(channel_index, nElements, dest);
709 if (res) {
710 IORLOG("ERROR: updateReportChannel() failed: %x", res);
711 goto finish;
712 }
713 break;
714
715 default:
716 IORLOG("ERROR updateReport unknown action!");
717 res = kIOReturnError;
718 goto finish;
719 }
720 }
721 }
722
723 // success
724 res = kIOReturnSuccess;
725
fe8ab488 726finish:
0a7de745 727 return res;
fe8ab488
A
728}
729
730
f427ee49 731OSSharedPtr<IOReportLegendEntry>
fe8ab488
A
732IOReporter::handleCreateLegend(void)
733{
f427ee49
A
734 OSSharedPtr<IOReportLegendEntry> legendEntry = nullptr;
735 OSSharedPtr<OSArray> channelIDs;
0a7de745
A
736
737 channelIDs = copyChannelIDs();
738
739 if (channelIDs) {
f427ee49 740 legendEntry = IOReporter::legendWith(channelIDs.get(), _channelNames.get(), _channelType, _unit);
0a7de745
A
741 }
742
743 return legendEntry;
fe8ab488
A
744}
745
746
747IOReturn
748IOReporter::setElementValues(int element_index,
0a7de745
A
749 IOReportElementValues *values,
750 uint64_t record_time /* = 0 */)
fe8ab488 751{
0a7de745
A
752 IOReturn res = kIOReturnError;
753
754 IOREPORTER_CHECK_LOCK();
755
756 if (record_time == 0) {
757 record_time = mach_absolute_time();
758 }
759
760 if (element_index >= _nElements || values == NULL) {
761 res = kIOReturnBadArgument;
762 goto finish;
763 }
764
765 memcpy(&_elements[element_index].values, values, sizeof(IOReportElementValues));
766
767 _elements[element_index].timestamp = record_time;
768
769 //IOREPORTER_DEBUG_ELEMENT(index);
770
771 res = kIOReturnSuccess;
772
fe8ab488 773finish:
0a7de745 774 return res;
fe8ab488
A
775}
776
777
778const IOReportElementValues*
779IOReporter::getElementValues(int element_index)
780{
0a7de745
A
781 IOReportElementValues *elementValues = NULL;
782
783 IOREPORTER_CHECK_LOCK();
784
785 if (element_index < 0 || element_index >= _nElements) {
786 IORLOG("ERROR getElementValues out of bounds!");
787 goto finish;
788 }
789
790 elementValues = &_elements[element_index].values;
791
fe8ab488 792finish:
0a7de745 793 return elementValues;
fe8ab488
A
794}
795
796
797IOReturn
798IOReporter::updateChannelValues(int channel_index)
799{
0a7de745 800 return kIOReturnSuccess;
fe8ab488
A
801}
802
803
804IOReturn
805IOReporter::updateReportChannel(int channel_index,
0a7de745
A
806 int *nElements,
807 IOBufferMemoryDescriptor *destination)
fe8ab488 808{
0a7de745
A
809 IOReturn res = kIOReturnError;
810 int start_element_idx, chElems;
811 size_t size2cpy;
812
813 res = kIOReturnBadArgument;
814 if (!nElements || !destination) {
815 goto finish;
816 }
817 if (channel_index > _nChannels) {
818 goto finish;
819 }
820
821 IOREPORTER_CHECK_LOCK();
822
823 res = kIOReturnOverrun;
824
825 start_element_idx = channel_index * _channelDimension;
826 if (start_element_idx >= _nElements) {
827 goto finish;
828 }
829
830 chElems = _elements[start_element_idx].channel_type.nelements;
831
832 // make sure we don't go beyond the end of _elements[_nElements-1]
833 if (start_element_idx + chElems > _nElements) {
834 goto finish;
835 }
836
837 PREFL_MEMOP_FAIL(chElems, IOReportElement);
838 size2cpy = (size_t)chElems * sizeof(IOReportElement);
839
840 // make sure there's space in the destination
841 if (size2cpy > (destination->getCapacity() - destination->getLength())) {
842 IORLOG("CRITICAL ERROR: Report Buffer Overflow (buffer cap %luB, length %luB, size2cpy %luB",
843 (unsigned long)destination->getCapacity(),
844 (unsigned long)destination->getLength(),
845 (unsigned long)size2cpy);
846 goto finish;
847 }
848
849 destination->appendBytes(&_elements[start_element_idx], size2cpy);
850 *nElements += chElems;
851
852 res = kIOReturnSuccess;
853
fe8ab488 854finish:
0a7de745 855 return res;
fe8ab488
A
856}
857
858
859IOReturn
860IOReporter::copyElementValues(int element_index,
0a7de745 861 IOReportElementValues *elementValues)
fe8ab488 862{
0a7de745
A
863 IOReturn res = kIOReturnError;
864
865 if (!elementValues) {
866 goto finish;
867 }
868
869 IOREPORTER_CHECK_LOCK();
870
871 if (element_index >= _nElements) {
872 IORLOG("ERROR getElementValues out of bounds!");
873 res = kIOReturnBadArgument;
874 goto finish;
875 }
876
877 memcpy(elementValues, &_elements[element_index].values, sizeof(IOReportElementValues));
878 res = kIOReturnSuccess;
fe8ab488
A
879
880finish:
0a7de745 881 return res;
fe8ab488
A
882}
883
884
885IOReturn
886IOReporter::getFirstElementIndex(uint64_t channel_id,
0a7de745 887 int *index)
fe8ab488 888{
0a7de745
A
889 IOReturn res = kIOReturnError;
890 int channel_index = 0, element_index = 0;
891
892 if (!index) {
893 goto finish;
894 }
895
896 res = getChannelIndices(channel_id, &channel_index, &element_index);
897
898 if (res == kIOReturnSuccess) {
899 *index = element_index;
900 }
fe8ab488
A
901
902finish:
0a7de745 903 return res;
fe8ab488
A
904}
905
906
907IOReturn
908IOReporter::getChannelIndex(uint64_t channel_id,
0a7de745 909 int *index)
fe8ab488 910{
0a7de745
A
911 IOReturn res = kIOReturnError;
912 int channel_index = 0, element_index = 0;
913
914 if (!index) {
915 goto finish;
916 }
917
918 res = getChannelIndices(channel_id, &channel_index, &element_index);
919
920 if (res == kIOReturnSuccess) {
921 *index = channel_index;
922 }
fe8ab488
A
923
924finish:
0a7de745 925 return res;
fe8ab488
A
926}
927
928
929IOReturn
930IOReporter::getChannelIndices(uint64_t channel_id,
0a7de745
A
931 int *channel_index,
932 int *element_index)
fe8ab488 933{
0a7de745
A
934 IOReturn res = kIOReturnNotFound;
935 int chIdx, elemIdx;
936
937 if (!channel_index || !element_index) {
938 goto finish;
939 }
940
941 for (chIdx = 0; chIdx < _nChannels; chIdx++) {
942 elemIdx = chIdx * _channelDimension;
943 if (elemIdx >= _nElements) {
944 IORLOG("ERROR getChannelIndices out of bounds!");
945 res = kIOReturnOverrun;
946 goto finish;
947 }
948
949 if (channel_id == _elements[elemIdx].channel_id) {
950 // The channel index does not care about the depth of elements...
951 *channel_index = chIdx;
952 *element_index = elemIdx;
953
954 res = kIOReturnSuccess;
955 goto finish;
956 }
957 }
fe8ab488
A
958
959finish:
0a7de745 960 return res;
fe8ab488
A
961}
962
963/********************************/
964/*** PRIVATE METHODS ***/
965/********************************/
966
967
968// copyChannelIDs relies on the caller to take lock
f427ee49 969OSSharedPtr<OSArray>
fe8ab488
A
970IOReporter::copyChannelIDs()
971{
0a7de745 972 int cnt, cnt2;
f427ee49
A
973 OSSharedPtr<OSArray> channelIDs;
974 OSSharedPtr<OSNumber> tmpNum;
0a7de745
A
975
976 channelIDs = OSArray::withCapacity((unsigned)_nChannels);
977
978 if (!channelIDs) {
f427ee49 979 return nullptr;
0a7de745
A
980 }
981
982 for (cnt = 0; cnt < _nChannels; cnt++) {
983 cnt2 = cnt * _channelDimension;
984
985 // Encapsulate the Channel ID in OSNumber
986 tmpNum = OSNumber::withNumber(_elements[cnt2].channel_id, 64);
987 if (!tmpNum) {
988 IORLOG("ERROR: Could not create array of channelIDs");
f427ee49 989 return nullptr;
0a7de745
A
990 }
991
f427ee49
A
992 channelIDs->setObject((unsigned)cnt, tmpNum.get());
993 tmpNum.reset();
0a7de745 994 }
fe8ab488 995
0a7de745 996 return channelIDs;
fe8ab488
A
997}
998
999
1000// DO NOT REMOVE THIS METHOD WHICH IS THE MAIN LEGEND CREATION FUNCTION
f427ee49 1001/*static */ OSSharedPtr<IOReportLegendEntry>
fe8ab488 1002IOReporter::legendWith(OSArray *channelIDs,
0a7de745
A
1003 OSArray *channelNames,
1004 IOReportChannelType channelType,
1005 IOReportUnit unit)
fe8ab488 1006{
0a7de745
A
1007 unsigned int cnt, chCnt;
1008 uint64_t type64;
f427ee49 1009 OSSharedPtr<OSNumber> tmpNum;
0a7de745 1010 const OSSymbol *tmpSymbol;
f427ee49
A
1011 OSSharedPtr<OSArray> channelLegendArray;
1012 OSSharedPtr<OSArray> tmpChannelArray;
1013 OSSharedPtr<OSDictionary> channelInfoDict;
1014 OSSharedPtr<IOReportLegendEntry> legendEntry = nullptr;
0a7de745
A
1015
1016 // No need to check validity of channelNames because param is optional
1017 if (!channelIDs) {
1018 goto finish;
1019 }
1020 chCnt = channelIDs->getCount();
1021
1022 channelLegendArray = OSArray::withCapacity(chCnt);
1023
1024 for (cnt = 0; cnt < chCnt; cnt++) {
1025 tmpChannelArray = OSArray::withCapacity(3);
1026
1027 // Encapsulate the Channel ID in OSNumber
1028 tmpChannelArray->setObject(kIOReportChannelIDIdx, channelIDs->getObject(cnt));
1029
1030 // Encapsulate the Channel Type in OSNumber
1031 memcpy(&type64, &channelType, sizeof(type64));
1032 tmpNum = OSNumber::withNumber(type64, 64);
1033 if (!tmpNum) {
1034 goto finish;
1035 }
f427ee49
A
1036 tmpChannelArray->setObject(kIOReportChannelTypeIdx, tmpNum.get());
1037 tmpNum.reset();
0a7de745
A
1038
1039 // Encapsulate the Channel Name in OSSymbol
1040 // Use channelNames if provided
1041 if (channelNames != NULL) {
1042 tmpSymbol = OSDynamicCast(OSSymbol, channelNames->getObject(cnt));
1043 if (tmpSymbol && tmpSymbol != gIOReportNoChannelName) {
1044 tmpChannelArray->setObject(kIOReportChannelNameIdx, tmpSymbol);
1045 } // Else, skip and leave name field empty
1046 }
1047
f427ee49
A
1048 channelLegendArray->setObject(cnt, tmpChannelArray.get());
1049 tmpChannelArray.reset();
0a7de745
A
1050 }
1051
1052 // Stuff the legend entry only if we have channels...
1053 if (channelLegendArray->getCount() != 0) {
1054 channelInfoDict = OSDictionary::withCapacity(1);
1055
1056 if (!channelInfoDict) {
1057 goto finish;
1058 }
1059
1060 tmpNum = OSNumber::withNumber(unit, 64);
1061 if (tmpNum) {
f427ee49 1062 channelInfoDict->setObject(kIOReportLegendUnitKey, tmpNum.get());
0a7de745
A
1063 }
1064
1065 legendEntry = OSDictionary::withCapacity(1);
1066
1067 if (legendEntry) {
f427ee49
A
1068 legendEntry->setObject(kIOReportLegendChannelsKey, channelLegendArray.get());
1069 legendEntry->setObject(kIOReportLegendInfoKey, channelInfoDict.get());
0a7de745
A
1070 }
1071 }
1072
fe8ab488 1073finish:
0a7de745 1074 return legendEntry;
fe8ab488 1075}