]> git.saurik.com Git - apple/xnu.git/blame_incremental - iokit/IOKit/IOReportMacros.h
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / IOKit / IOReportMacros.h
... / ...
CommitLineData
1/*
2 * Copyright (c) 2012-2020 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#ifndef _IOREPORT_MACROS_H_
30#define _IOREPORT_MACROS_H_
31
32#include "IOReportTypes.h"
33#include <string.h>
34
35#ifdef __cplusplus
36extern "C" {
37#endif
38
39#ifndef IOREPORT_ABORT
40#define IOREPORT_ABORT panic
41#endif
42
43/*
44 * Background
45 *
46 * These macros allow non-I/O Kit software to generate IOReporting
47 * reports. Clients must prevent concurrent access to any given
48 * report buffer from multiple threads.
49 *
50 * While these macros allow non-I/O Kit software to participate
51 * in IOReporting, an IOService instance must lend its driver ID,
52 * respond to the appropriate IOService overrides, and shuttle
53 * data back and forth. In some cases, it may be useful to have
54 * the I/O Kit driver initialize the report buffer with the
55 * appropriate macro.
56 */
57
58
59/* ----- Reporting Single Integers (SimpleReport) ----- */
60
61/*
62 * The buffer size required for a SimpleReport.
63 */
64
65#define SIMPLEREPORT_BUFSIZE (sizeof(IOReportElement))
66
67
68/*
69 * Initialize a buffer to hold a SimpleReport.
70 *
71 * void* buffer - ptr to SIMPLEREPORT_BUFSIZE bytes
72 * size_t bufSize - sanity check of buffer's size
73 * uint64_t providerID - registry Entry ID of the reporting service
74 * uint64_t channelID - the report's channel ID
75 * IOReportCategories categories - categories of this channel
76 *
77 * If the buffer is not of sufficient size, the macro calls IOREPORT_ABORT().
78 * If that returns, the buffer is left full of '&'.
79 */
80
81#define SIMPLEREPORT_INIT(buf, bufSize, providerID, channelID, cats) \
82do { \
83 memset((buf), '&', (bufSize)); \
84 IOReportElement *__elem = (IOReportElement *)(buf); \
85 IOSimpleReportValues *__vals; \
86 if ((bufSize) >= SIMPLEREPORT_BUFSIZE) { \
87 __elem->provider_id = (providerID); \
88 __elem->channel_id = (channelID); \
89 __elem->channel_type.report_format = kIOReportFormatSimple; \
90 __elem->channel_type.reserved = 0; \
91 __elem->channel_type.categories = (cats); \
92 __elem->channel_type.nelements = 1; \
93 __elem->channel_type.element_idx = 0; \
94 __elem->timestamp = 0; \
95 __vals = (IOSimpleReportValues*)&__elem->values; \
96 __vals->simple_value = kIOReportInvalidIntValue; \
97 } \
98 else { \
99 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
100 } \
101} while(0)
102
103
104/*
105 * Set a SimpleReport to a new value.
106 *
107 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
108 * int64_t new_value - new value for the report
109 */
110
111#define SIMPLEREPORT_SETVALUE(simp_buf, new_value) \
112do { \
113 IOReportElement *__elem = (IOReportElement *)(simp_buf); \
114 IOSimpleReportValues *__vals; \
115 __vals = (IOSimpleReportValues*)&__elem->values; \
116 __vals->simple_value = (new_value); \
117} while(0)
118
119
120/*
121 * Increment the value of a SimpleReport.
122 *
123 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
124 * int64_t increment - amount by which to increment the value
125 */
126#define SIMPLEREPORT_INCREMENTVALUE(simp_buf, new_value) \
127do { \
128 IOReportElement *__elem = (IOReportElement *)(simp_buf); \
129 IOSimpleReportValues *__vals; \
130 __vals = (IOSimpleReportValues*)&__elem->values; \
131 __vals->simple_value += (new_value); \
132} while(0)
133
134
135/*
136 * Prepare a SimpleReport for
137 * IOService::updateReport(kIOReportCopyChannelData...)
138 *
139 * void* simp_buf - Ptr to memory updated by SIMPLEREPORT_SETVALUE()
140 * void* ptr2cpy - On return, 'ptr2cpy' points to the memory that needs to be
141 * copied for kIOReportCopyChannelData.
142 * size_t size2cpy - On return, 'size2cpy' is set to the size of the report
143 * data that needs to be copied for kIOReportCopyChannelData.
144 */
145
146#define SIMPLEREPORT_UPDATEPREP(simp_buf, ptr2cpy, size2cpy) \
147do { \
148 (ptr2cpy) = (simp_buf); \
149 (size2cpy) = sizeof(IOReportElement); \
150} while(0)
151
152
153/*
154 * Update the result field received as a parameter for
155 * kIOReportGetDimensions & kIOReportCopyChannelData actions.
156 *
157 * IOReportConfigureAction action - configure/updateReport() 'action' param
158 * void* result - configure/updateReport() 'result' param
159 */
160
161#define SIMPLEREPORT_UPDATERES(action, result) \
162do { \
163 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
164 int *__nElements = (int *)(result); \
165 *__nElements += 1; \
166 } \
167} while (0)
168
169
170/*
171 * Get the 64-bit channel ID of a SimpleReport.
172 *
173 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
174 */
175
176#define SIMPLEREPORT_GETCHID(simp_buf) \
177 (((IOReportElement *)(simp_buf))->channel_id)
178
179/*
180 * Get the IOReportChannelType of a SimpleReport.
181 *
182 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
183 */
184
185#define SIMPLEREPORT_GETCHTYPE(simp_buf) \
186 (*(uint64_t*)&(((IOReportElement *)(simp_buf))->channel_type))
187
188
189/*
190 * Get the integer value of a SimpleReport.
191 *
192 * void* simp_buf - memory initialized by SIMPLEREPORT_INIT()
193 */
194
195#define SIMPLEREPORT_GETVALUE(simp_buf) \
196 (((IOSimpleReportValues*)&(((IOReportElement*)(simp_buf))->values)) \
197 ->simple_value)
198
199
200/* ----- State Machine Reporting (StateReport) ----- */
201
202// Internal struct for StateReport
203typedef struct {
204 uint16_t curr_state;
205 uint64_t update_ts;
206 IOReportElement elem[]; // Array of elements
207} IOStateReportInfo;
208
209/*
210 * Determine the size required for a StateReport buffer.
211 *
212 * int nstates - number of states to be reported
213 */
214#define STATEREPORT_BUFSIZE(nstates) \
215 (sizeof(IOStateReportInfo) + (nstates) * sizeof(IOReportElement))
216
217
218/*
219 * Initialize a StateReport buffer.
220 *
221 * uint16_t nstates - number of states to be reported
222 * void* buffer - ptr to STATEREPORT_BUFSIZE(nstates) bytes
223 * size_t bufSize - sanity check of buffer's size
224 * uint64_t providerID - registry Entry ID of the reporting service
225 * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
226 * IOReportCategories categories - categories of this channel
227 *
228 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT.
229 * If that returns, the buffer is left full of '&'.
230 */
231#define STATEREPORT_INIT(nstates, buf, bufSize, providerID, channelID, cats) \
232do { \
233 memset((buf), '&', (bufSize)); \
234 IOStateReportInfo *__info = (IOStateReportInfo *)(buf); \
235 IOStateReportValues *__rep; \
236 IOReportElement *__elem; \
237 if ((bufSize) >= STATEREPORT_BUFSIZE(nstates)) { \
238 for (uint16_t __no = 0; __no < (nstates); __no++) { \
239 __elem = &(__info->elem[__no]); \
240 __rep = (IOStateReportValues *) &(__elem->values); \
241 __elem->provider_id = (providerID); \
242 __elem->channel_id = (channelID); \
243 __elem->channel_type.report_format = kIOReportFormatState; \
244 __elem->channel_type.reserved = 0; \
245 __elem->channel_type.categories = (cats); \
246 __elem->channel_type.nelements = (nstates); \
247 __elem->channel_type.element_idx = __no; \
248 __elem->timestamp = 0; \
249 __rep->state_id = __no; \
250 __rep->intransitions = 0; \
251 __rep->upticks = 0; \
252 __rep->last_intransition = 0; \
253 } \
254 __info->curr_state = 0; \
255 __info->update_ts = 0; \
256 } \
257 else { \
258 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
259 } \
260} while(0)
261
262/*
263 * Initialize the state id field of a state with the specified value. By
264 * default, STATEREPORT_INIT() initializes the state IDs with the index of
265 * that state. This macro can be used to provide a more descriptive state id.
266 *
267 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
268 * unsigned stateIdx - index of the state, out of bounds -> no-op
269 * uint64_t stateID - new state id, see IOREPORT_MAKEID()
270 */
271#define STATEREPORT_SETSTATEID(state_buf, stateIdx, stateID) \
272do { \
273 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
274 IOStateReportValues *__rep; \
275 if ((stateIdx) < __info->elem[0].channel_type.nelements) { \
276 __rep = (IOStateReportValues*) &(__info->elem[(stateIdx)].values); \
277 __rep->state_id = (stateID); \
278 } \
279} while (0)
280
281
282/*
283 * Set the state of a StateReport.
284 *
285 * void* state_buf - pointer to memory initialized by STATEREPORT_INIT()
286 * unsigned newStateIdx - index of new state, out of bounds -> no-op
287 * uint64_t changeTime - time at which the transition occurred
288 */
289#define STATEREPORT_SETSTATE(state_buf, newStateIdx, changeTime) \
290do { \
291 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
292 IOStateReportValues *__rep; \
293 if ((newStateIdx) < __info->elem[0].channel_type.nelements ) { \
294 __rep = (IOStateReportValues*) &(__info->elem[__info->curr_state].values); \
295 if (__info->update_ts) \
296 __rep->upticks += (changeTime) - __info->update_ts; \
297 __info->elem[(newStateIdx)].timestamp = (changeTime); \
298 __rep = (IOStateReportValues*) &(__info->elem[(newStateIdx)].values); \
299 __rep->intransitions++; \
300 __info->curr_state = (newStateIdx); \
301 __info->update_ts = (changeTime); \
302 } \
303} while(0)
304
305/*
306 * Prepare a StateReport for
307 * IOService::updateReport(kIOReportCopyChannelData...)
308 *
309 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
310 * uint64_t currentTime - current timestamp
311 * void* ptr2cpy - filled in with pointer to buffer to be copied out
312 * size_t size2cpy - filled in with the size of the buffer to copy out
313 */
314#define STATEREPORT_UPDATEPREP(state_buf, currentTime, ptr2cpy, size2cpy) \
315do { \
316 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
317 IOReportElement *__elem; \
318 IOStateReportValues *__state; \
319 (size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement); \
320 (ptr2cpy) = (void *) &__info->elem[0]; \
321 if (__info->update_ts) { \
322 __elem = &__info->elem[__info->curr_state]; \
323 __state = (IOStateReportValues *)&__elem->values; \
324 __elem->timestamp = (currentTime); \
325 __state->upticks += (currentTime) - __info->update_ts; \
326 __info->update_ts = (currentTime); \
327 } \
328} while(0)
329
330/*
331 * Update the result field received as a parameter for kIOReportGetDimensions &
332 * kIOReportCopyChannelData actions.
333 *
334 * void* state_buf - memory initialized by STATEREPORT_INIT()
335 * IOReportConfigureAction action - configure/updateReport() 'action'
336 * void* result - configure/updateReport() 'result'
337 */
338
339#define STATEREPORT_UPDATERES(state_buf, action, result) \
340do { \
341 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
342 IOReportElement *__elem; \
343 int *__nElements = (int *)(result); \
344 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
345 __elem = &(__info->elem[0]); \
346 *__nElements += __elem->channel_type.nelements; \
347 } \
348} while (0)
349
350
351/*
352 * Get the 64-bit channel ID of a StateReport.
353 *
354 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
355 */
356#define STATEREPORT_GETCHID(state_buf) \
357 (((IOStateReportInfo *)(state_buf))->elem[0].channel_id)
358
359/*
360 * Get the IOReportChannelType of a StateReport.
361 *
362 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
363 */
364#define STATEREPORT_GETCHTYPE(state_buf) \
365 (*(uint64_t*)&(((IOStateReportInfo *)(state_buf))->elem[0].channel_type))
366
367/*
368 * Get the number of transitions into a given state.
369 *
370 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
371 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
372 *
373 */
374#define STATEREPORT_GETTRANSITIONS(state_buf, stateIdx) \
375 (((stateIdx) < ((IOStateReportInfo *)(state_buf))->elem[0].channel_type.nelements) \
376 ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->intransitions \
377 : kIOReportInvalidValue)
378
379/*
380 * Get the total number of ticks spent in a given state.
381 *
382 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
383 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
384 */
385#define STATEREPORT_GETTICKS(state_buf, stateIdx) \
386 (((stateIdx) < ((IOStateReportInfo*)(state_buf))->elem[0].channel_type.nelements) \
387 ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->upticks \
388 : kIOReportInvalidValue)
389
390
391/* ----- Reporting an Array of Integers (SimpleArrayReport) ----- */
392
393/*
394 * Determine the buffer size for a SimpleArrayReport.
395 *
396 * int nValues - number of values to be reported
397 */
398
399#define SIMPLEARRAY_BUFSIZE(nValues) \
400 ((((nValues)/IOR_VALUES_PER_ELEMENT) + (((nValues) % IOR_VALUES_PER_ELEMENT) ? 1:0)) \
401 * sizeof(IOReportElement))
402
403/*
404 * Initialize a buffer for use as a SimpleArrayReport.
405 *
406 * int nValues - number of elements to be reported
407 * void* buf - ptr to SIMPLEARRAY_BUFSIZE(nValues) bytes
408 * size_t bufSize - sanity check of buffer's size
409 * uint64_t providerID - registry Entry ID of the reporting service
410 * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
411 * IOReportCategories categories - categories of this channel
412 *
413 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT().
414 * If that returns, the buffer is left full of '&'.
415 */
416
417#define SIMPLEARRAY_INIT(nValues, buf, bufSize, providerID, channelID, cats) \
418do { \
419 memset((buf), '&', (bufSize)); \
420 IOSimpleArrayReportValues *__rep; \
421 IOReportElement *__elem; \
422 uint32_t __nElems = (((nValues) / IOR_VALUES_PER_ELEMENT) + \
423 (((nValues) % IOR_VALUES_PER_ELEMENT) ? 1 : 0)); \
424 if ((bufSize) >= SIMPLEARRAY_BUFSIZE(nValues)) { \
425 for (unsigned __no = 0; __no < __nElems; __no++) { \
426 __elem = &(((IOReportElement *)(buf))[__no]); \
427 __rep = (IOSimpleArrayReportValues *) &(__elem->values); \
428 __elem->provider_id = (providerID); \
429 __elem->channel_id = (channelID); \
430 __elem->channel_type.report_format = kIOReportFormatSimpleArray; \
431 __elem->channel_type.reserved = 0; \
432 __elem->channel_type.categories = (cats); \
433 __elem->channel_type.nelements = (__nElems); \
434 __elem->channel_type.element_idx = __no; \
435 __elem->timestamp = 0; \
436 __rep->simple_values[0] = kIOReportInvalidIntValue; \
437 __rep->simple_values[1] = kIOReportInvalidIntValue; \
438 __rep->simple_values[2] = kIOReportInvalidIntValue; \
439 __rep->simple_values[3] = kIOReportInvalidIntValue; \
440 } \
441 } \
442 else { \
443 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
444 } \
445} while(0)
446
447
448/* SimpleArrayReport helpers */
449
450 #define __SA_FINDREP(array_buf, idx) \
451 IOSimpleArrayReportValues *__rep; \
452 IOReportElement *__elem; \
453 unsigned __elemIdx = (idx) / IOR_VALUES_PER_ELEMENT; \
454 unsigned __valueIdx = (idx) % IOR_VALUES_PER_ELEMENT; \
455 __elem = &(((IOReportElement *)(array_buf))[0]); \
456 if (__elemIdx < __elem->channel_type.nelements) { \
457 __elem = &(((IOReportElement *)(array_buf))[__elemIdx]); \
458 __rep = (IOSimpleArrayReportValues *) &(__elem->values); \
459
460 #define __SA_MAXINDEX(array_buf) \
461 ((((IOReportElement*)(array_buf))->channel_type.nelements) \
462 * IOR_VALUES_PER_ELEMENT) - 1
463
464/*
465 * Set a value at a specified index in a SimpleArrayReport.
466 *
467 * void* array_bufbuf - ptr to memory initialized by SIMPLEARRAY_INIT()
468 * unsigned idx - array index, out of bounds -> no-op
469 * uint64_t newValue - new value to be stored at array[idx]
470 */
471#define SIMPLEARRAY_SETVALUE(array_buf, idx, newValue) \
472do { \
473 __SA_FINDREP((array_buf), (idx)) \
474 __rep->simple_values[__valueIdx] = (newValue); \
475 } \
476} while(0)
477
478/*
479 * Increment an array value within a SimpleArrayReport.
480 *
481 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
482 * unsigned idx - array index to increment, out of bounds -> no-op
483 * int64_t value - amount by which to increment array[idx]
484 */
485#define SIMPLEARRAY_INCREMENTVALUE(array_buf, idx, value) \
486do { \
487 __SA_FINDREP((array_buf), (idx)) \
488 __rep->simple_values[__valueIdx] += (value); \
489 } \
490} while(0)
491
492
493/*
494 * Prepare a SimpleArrayReport for
495 * IOService::updateReport(kIOReportCopyChannelData...)
496 *
497 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
498 * void* ptr2cpy - filled in with pointer to buffer to be copied out
499 * size_t size2cpy - filled in with the size of the buffer to copy out
500 */
501
502#define SIMPLEARRAY_UPDATEPREP(array_buf, ptr2cpy, size2cpy) \
503do { \
504 IOReportElement *__elem; \
505 __elem = &(((IOReportElement *)(array_buf))[0]); \
506 (ptr2cpy) = (void *) (array_buf); \
507 (size2cpy) = __elem->channel_type.nelements * sizeof(IOReportElement); \
508} while(0)
509
510
511/*
512 * Update the result field received as a parameter for kIOReportGetDimensions &
513 * kIOReportCopyChannelData actions.
514 *
515 * void* array_buf - memory initialized by SIMPLEARRAY_INIT()
516 * IOReportConfigureAction action - configure/updateReport() 'action'
517 * void* result - configure/updateReport() 'result'
518 */
519
520#define SIMPLEARRAY_UPDATERES(array_buf, action, result) \
521do { \
522 IOReportElement *__elem; \
523 int *__nElements = (int *)(result); \
524 __elem = &(((IOReportElement *)(array_buf))[0]); \
525 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
526 *__nElements += __elem->channel_type.nelements; \
527 } \
528} while (0)
529
530
531/*
532 * Get the 64-bit channel ID of a SimpleArrayReport.
533 *
534 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
535 */
536#define SIMPLEARRAY_GETCHID(array_buf) \
537 (((IOReportElement *)(array_buf))->channel_id)
538
539
540/*
541 * Get the IOReportChannelType of a SimpleArrayReport.
542 *
543 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
544 */
545#define SIMPLEARRAY_GETCHTYPE(array_buf) \
546 (*(uint64_t*)&(((IOReportElement *)(array_buf))->channel_type))
547
548/*
549 * Get a value from a SimpleArrayReport.
550 *
551 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
552 * unsigned idx - index of the value, out of bounds -> kIOReportInvalidValue
553 */
554#define SIMPLEARRAY_GETVALUE(array_buf, idx) \
555 (((idx) > __SA_MAXINDEX(array_buf) || (idx) < 0) ? kIOReportInvalidIntValue : \
556 ((IOSimpleArrayReportValues*)&( \
557 ((IOReportElement*)(array_buf))[(idx) / IOR_VALUES_PER_ELEMENT].values)) \
558 ->simple_values[(idx) % IOR_VALUES_PER_ELEMENT])
559
560
561/* ----- Histogram Reporting (HistogramReport) ----- */
562
563// Internal struct for HistogramReport
564typedef struct {
565 int bucketWidth;
566 IOReportElement elem[]; // Array of elements
567} IOHistReportInfo;
568
569/*
570 * Determine the size required for a HistogramReport buffer.
571 *
572 * int nbuckets - number of buckets in the histogram
573 */
574#define HISTREPORT_BUFSIZE(nbuckets) \
575 (sizeof(IOHistReportInfo) + ((nbuckets) * sizeof(IOReportElement)))
576
577/*
578 * Initialize a HistogramReport buffer. Supports only linear scale histogram.
579 *
580 * uint16_t nbuckets - number of buckets data is combined into
581 * uint32_t bucketWidth - size of each bucket
582 * void* buffer - ptr to HISTREPORT_BUFSIZE(nbuckets) bytes
583 * size_t bufSize - sanity check of buffer's size
584 * uint64_t providerID - registry Entry ID of the reporting service
585 * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
586 * IOReportCategories categories - categories of this channel
587 *
588 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT.
589 * If that returns, the buffer is left full of '&'.
590 */
591#define HISTREPORT_INIT(nbuckets, bktSize, buf, bufSize, providerID, channelID, cats) \
592do { \
593 memset((buf), '&', (bufSize)); \
594 IOHistReportInfo *__info = (IOHistReportInfo *)(buf); \
595 IOReportElement *__elem; \
596 IOHistogramReportValues *__rep; \
597 if ((bufSize) >= HISTREPORT_BUFSIZE(nbuckets)) { \
598 __info->bucketWidth = (bktSize); \
599 for (uint16_t __no = 0; __no < (nbuckets); __no++) { \
600 __elem = &(__info->elem[__no]); \
601 __rep = (IOHistogramReportValues *) &(__elem->values); \
602 __elem->provider_id = (providerID); \
603 __elem->channel_id = (channelID); \
604 __elem->channel_type.report_format = kIOReportFormatHistogram; \
605 __elem->channel_type.reserved = 0; \
606 __elem->channel_type.categories = (cats); \
607 __elem->channel_type.nelements = (nbuckets); \
608 __elem->channel_type.element_idx = __no; \
609 __elem->timestamp = 0; \
610 memset(__rep, '\0', sizeof(IOHistogramReportValues)); \
611 } \
612 } \
613 else { \
614 IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
615 } \
616} while (0)
617
618/*
619 * Update histogram with a new value.
620 *
621 *
622 * void* hist_buf - pointer to memory initialized by HISTREPORT_INIT()
623 * int64_t value - new value to add to the histogram
624 */
625#define HISTREPORT_TALLYVALUE(hist_buf, value) \
626do { \
627 IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
628 IOReportElement *__elem; \
629 IOHistogramReportValues *__rep; \
630 for (unsigned __no = 0; __no < __info->elem[0].channel_type.nelements; __no++) { \
631 if ((value) <= __info->bucketWidth * (__no+1)) { \
632 __elem = &(__info->elem[__no]); \
633 __rep = (IOHistogramReportValues *) &(__elem->values); \
634 if (__rep->bucket_hits == 0) { \
635 __rep->bucket_min = __rep->bucket_max = (value); \
636 } \
637 else if ((value) < __rep->bucket_min) { \
638 __rep->bucket_min = (value); \
639 } \
640 else if ((value) > __rep->bucket_max) { \
641 __rep->bucket_max = (value); \
642 } \
643 __rep->bucket_sum += (value); \
644 __rep->bucket_hits++; \
645 break; \
646 } \
647 } \
648} while (0)
649
650/*
651 * Prepare a HistogramReport for
652 * IOService::updateReport(kIOReportCopyChannelData...)
653 *
654 * void* array_buf - ptr to memory initialized by HISTREPORT_INIT()
655 * void* ptr2cpy - filled in with pointer to buffer to be copied out
656 * size_t size2cpy - filled in with the size of the buffer to copy out
657 */
658
659#define HISTREPORT_UPDATEPREP(hist_buf, ptr2cpy, size2cpy) \
660do { \
661 IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
662 (size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement); \
663 (ptr2cpy) = (void *) &__info->elem[0]; \
664} while(0)
665
666
667/*
668 * Update the result field received as a parameter for kIOReportGetDimensions &
669 * kIOReportCopyChannelData actions.
670 *
671 * void* array_buf - memory initialized by HISTREPORT_INIT()
672 * IOReportConfigureAction action - configure/updateReport() 'action'
673 * void* result - configure/updateReport() 'result'
674 */
675
676#define HISTREPORT_UPDATERES(hist_buf, action, result) \
677do { \
678 IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
679 int *__nElements = (int *)(result); \
680 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
681 *__nElements += __info->elem[0].channel_type.nelements; \
682 } \
683} while (0)
684
685/*
686 * Get the 64-bit channel ID of a HistogramReport.
687 *
688 * void* hist_buf - ptr to memory initialized by HISTREPORT_INIT()
689 */
690#define HISTREPORT_GETCHID(hist_buf) \
691 (((IOHistReportInfo *)(hist_buf))->elem[0].channel_id)
692
693/*
694 * Get the IOReportChannelType of a HistogramReport.
695 *
696 * void* hist_buf - ptr to memory initialized by HISTREPORT_INIT()
697 */
698#define HISTREPORT_GETCHTYPE(hist_buf) \
699 (*(uint64_t*)&(((IOHistReportInfo *)(hist_buf))->elem[0].channel_type))
700
701#ifdef __cplusplus
702}
703#endif
704
705#endif // _IOREPORT_MACROS_H_