/*
* Copyright (c) 2012-2020 Apple Computer, Inc. All Rights Reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef _IOREPORT_MACROS_H_
#define _IOREPORT_MACROS_H_
#include "IOReportTypes.h"
#include <string.h>
#include <os/overflow.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef IOREPORT_ABORT
#define IOREPORT_ABORT panic
#endif
/*
* Background
*
* These macros allow non-I/O Kit software to generate IOReporting
* reports. Clients must prevent concurrent access to any given
* report buffer from multiple threads.
*
* While these macros allow non-I/O Kit software to participate
* in IOReporting, an IOService instance must lend its driver ID,
* respond to the appropriate IOService overrides, and shuttle
* data back and forth. In some cases, it may be useful to have
* the I/O Kit driver initialize the report buffer with the
* appropriate macro.
*/
/* ----- Reporting Single Integers (SimpleReport) ----- */
/*
* The buffer size required for a SimpleReport.
*/
#define SIMPLEREPORT_BUFSIZE (sizeof(IOReportElement))
/*
* Initialize a buffer to hold a SimpleReport.
*
* void* buffer - ptr to SIMPLEREPORT_BUFSIZE bytes
* size_t bufSize - sanity check of buffer's size
* uint64_t providerID - registry Entry ID of the reporting service
* uint64_t channelID - the report's channel ID
* IOReportCategories categories - categories of this channel
*
* If the buffer is not of sufficient size, the macro calls IOREPORT_ABORT().
* If that returns, the buffer is left full of '&'.
*/
#define SIMPLEREPORT_INIT(buf, bufSize, providerID, channelID, cats) \
do { \
memset((buf), '&', (bufSize)); \
IOReportElement *__elem = (IOReportElement *)(buf); \
IOSimpleReportValues *__vals; \
if ((bufSize) >= SIMPLEREPORT_BUFSIZE) { \
__elem->provider_id = (providerID); \
__elem->channel_id = (channelID); \
__elem->channel_type.report_format = kIOReportFormatSimple; \
__elem->channel_type.reserved = 0; \
__elem->channel_type.categories = (cats); \
__elem->channel_type.nelements = 1; \
__elem->channel_type.element_idx = 0; \
__elem->timestamp = 0; \
__vals = (IOSimpleReportValues*)&__elem->values; \
__vals->simple_value = kIOReportInvalidIntValue; \
} \
else { \
IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
} \
} while(0)
/*
* Set a SimpleReport to a new value.
*
* void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
* int64_t new_value - new value for the report
*/
#define SIMPLEREPORT_SETVALUE(simp_buf, new_value) \
do { \
IOReportElement *__elem = (IOReportElement *)(simp_buf); \
IOSimpleReportValues *__vals; \
__vals = (IOSimpleReportValues*)&__elem->values; \
__vals->simple_value = (new_value); \
} while(0)
/*
* Increment the value of a SimpleReport.
*
* void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
* int64_t increment - amount by which to increment the value
*/
#define SIMPLEREPORT_INCREMENTVALUE(simp_buf, increment_by) \
do { \
IOReportElement *__elem = (IOReportElement *)(simp_buf); \
IOSimpleReportValues *__vals; \
__vals = (IOSimpleReportValues*)&__elem->values; \
int64_t __simple_value = INT64_MAX; \
if (os_add_overflow(__vals->simple_value, (increment_by), &__simple_value)) { \
__vals->simple_value = INT64_MAX; \
} else { \
__vals->simple_value = __simple_value; \
} \
} while(0)
/*
* Prepare a SimpleReport for
* IOService::updateReport(kIOReportCopyChannelData...)
*
* void* simp_buf - Ptr to memory updated by SIMPLEREPORT_SETVALUE()
* void* ptr2cpy - On return, 'ptr2cpy' points to the memory that needs to be
* copied for kIOReportCopyChannelData.
* size_t size2cpy - On return, 'size2cpy' is set to the size of the report
* data that needs to be copied for kIOReportCopyChannelData.
*/
#define SIMPLEREPORT_UPDATEPREP(simp_buf, ptr2cpy, size2cpy) \
do { \
(ptr2cpy) = (simp_buf); \
(size2cpy) = sizeof(IOReportElement); \
} while(0)
/*
* Update the result field received as a parameter for
* kIOReportGetDimensions & kIOReportCopyChannelData actions.
*
* IOReportConfigureAction action - configure/updateReport() 'action' param
* void* result - configure/updateReport() 'result' param
*/
#define SIMPLEREPORT_UPDATERES(action, result) \
do { \
if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
int *__nElements = (int *)(result); \
*__nElements += 1; \
} \
} while (0)
/*
* Get the 64-bit channel ID of a SimpleReport.
*
* void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
*/
#define SIMPLEREPORT_GETCHID(simp_buf) \
(((IOReportElement *)(simp_buf))->channel_id)
/*
* Get the IOReportChannelType of a SimpleReport.
*
* void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
*/
#define SIMPLEREPORT_GETCHTYPE(simp_buf) \
(*(uint64_t*)&(((IOReportElement *)(simp_buf))->channel_type))
/*
* Get the integer value of a SimpleReport.
*
* void* simp_buf - memory initialized by SIMPLEREPORT_INIT()
*/
#define SIMPLEREPORT_GETVALUE(simp_buf) \
(((IOSimpleReportValues*)&(((IOReportElement*)(simp_buf))->values)) \
->simple_value)
/* ----- State Machine Reporting (StateReport) ----- */
// Internal struct for StateReport
typedef struct {
uint16_t curr_state;
uint64_t update_ts;
IOReportElement elem[]; // Array of elements
} IOStateReportInfo;
/*
* Determine the size required for a StateReport buffer.
*
* int nstates - number of states to be reported
*/
#define STATEREPORT_BUFSIZE(nstates) \
(sizeof(IOStateReportInfo) + (nstates) * sizeof(IOReportElement))
/*
* Initialize a StateReport buffer.
*
* uint16_t nstates - number of states to be reported
* void* buffer - ptr to STATEREPORT_BUFSIZE(nstates) bytes
* size_t bufSize - sanity check of buffer's size
* uint64_t providerID - registry Entry ID of the reporting service
* uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
* IOReportCategories categories - categories of this channel
*
* If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT.
* If that returns, the buffer is left full of '&'.
*/
#define STATEREPORT_INIT(nstates, buf, bufSize, providerID, channelID, cats) \
do { \
memset((buf), '&', (bufSize)); \
IOStateReportInfo *__info = (IOStateReportInfo *)(buf); \
IOStateReportValues *__rep; \
IOReportElement *__elem; \
if ((bufSize) >= STATEREPORT_BUFSIZE(nstates)) { \
for (uint16_t __no = 0; __no < (nstates); __no++) { \
__elem = &(__info->elem[__no]); \
__rep = (IOStateReportValues *) &(__elem->values); \
__elem->provider_id = (providerID); \
__elem->channel_id = (channelID); \
__elem->channel_type.report_format = kIOReportFormatState; \
__elem->channel_type.reserved = 0; \
__elem->channel_type.categories = (cats); \
__elem->channel_type.nelements = (nstates); \
__elem->channel_type.element_idx = __no; \
__elem->timestamp = 0; \
__rep->state_id = __no; \
__rep->intransitions = 0; \
__rep->upticks = 0; \
__rep->last_intransition = 0; \
} \
__info->curr_state = 0; \
__info->update_ts = 0; \
} \
else { \
IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
} \
} while(0)
/*
* Initialize the state id field of a state with the specified value. By
* default, STATEREPORT_INIT() initializes the state IDs with the index of
* that state. This macro can be used to provide a more descriptive state id.
*
* void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
* unsigned stateIdx - index of the state, out of bounds -> no-op
* uint64_t stateID - new state id, see IOREPORT_MAKEID()
*/
#define STATEREPORT_SETSTATEID(state_buf, stateIdx, stateID) \
do { \
IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
IOStateReportValues *__rep; \
if ((stateIdx) < __info->elem[0].channel_type.nelements) { \
__rep = (IOStateReportValues*) &(__info->elem[(stateIdx)].values); \
__rep->state_id = (stateID); \
} \
} while (0)
/*
* Set the state of a StateReport.
*
* void* state_buf - pointer to memory initialized by STATEREPORT_INIT()
* unsigned newStateIdx - index of new state, out of bounds -> no-op
* uint64_t changeTime - time at which the transition occurred
*/
#define STATEREPORT_SETSTATE(state_buf, newStateIdx, changeTime) \
do { \
IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
IOStateReportValues *__rep; \
if ((newStateIdx) < __info->elem[0].channel_type.nelements ) { \
__rep = (IOStateReportValues*) &(__info->elem[__info->curr_state].values); \
if (__info->update_ts) \
__rep->upticks += (changeTime) - __info->update_ts; \
__info->elem[(newStateIdx)].timestamp = (changeTime); \
__rep = (IOStateReportValues*) &(__info->elem[(newStateIdx)].values); \
__rep->intransitions++; \
__info->curr_state = (newStateIdx); \
__info->update_ts = (changeTime); \
} \
} while(0)
/*
* Prepare a StateReport for
* IOService::updateReport(kIOReportCopyChannelData...)
*
* void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
* uint64_t currentTime - current timestamp
* void* ptr2cpy - filled in with pointer to buffer to be copied out
* size_t size2cpy - filled in with the size of the buffer to copy out
*/
#define STATEREPORT_UPDATEPREP(state_buf, currentTime, ptr2cpy, size2cpy) \
do { \
IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
IOReportElement *__elem; \
IOStateReportValues *__state; \
(size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement); \
(ptr2cpy) = (void *) &__info->elem[0]; \
if (__info->update_ts) { \
__elem = &__info->elem[__info->curr_state]; \
__state = (IOStateReportValues *)&__elem->values; \
__elem->timestamp = (currentTime); \
__state->upticks += (currentTime) - __info->update_ts; \
__info->update_ts = (currentTime); \
} \
} while(0)
/*
* Update the result field received as a parameter for kIOReportGetDimensions &
* kIOReportCopyChannelData actions.
*
* void* state_buf - memory initialized by STATEREPORT_INIT()
* IOReportConfigureAction action - configure/updateReport() 'action'
* void* result - configure/updateReport() 'result'
*/
#define STATEREPORT_UPDATERES(state_buf, action, result) \
do { \
IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
IOReportElement *__elem; \
int *__nElements = (int *)(result); \
if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
__elem = &(__info->elem[0]); \
if (os_add_overflow(*__nElements, __elem->channel_type.nelements, __nElements)) { \
*__nElements = INT_MAX; \
} \
} \
} while (0)
/*
* Get the 64-bit channel ID of a StateReport.
*
* void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
*/
#define STATEREPORT_GETCHID(state_buf) \
(((IOStateReportInfo *)(state_buf))->elem[0].channel_id)
/*
* Get the IOReportChannelType of a StateReport.
*
* void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
*/
#define STATEREPORT_GETCHTYPE(state_buf) \
(*(uint64_t*)&(((IOStateReportInfo *)(state_buf))->elem[0].channel_type))
/*
* Get the number of transitions into a given state.
*
* void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
* unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
*
*/
#define STATEREPORT_GETTRANSITIONS(state_buf, stateIdx) \
(((stateIdx) < ((IOStateReportInfo *)(state_buf))->elem[0].channel_type.nelements) \
? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->intransitions \
: kIOReportInvalidValue)
/*
* Get the total number of ticks spent in a given state.
*
* void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
* unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
*/
#define STATEREPORT_GETTICKS(state_buf, stateIdx) \
(((stateIdx) < ((IOStateReportInfo*)(state_buf))->elem[0].channel_type.nelements) \
? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->upticks \
: kIOReportInvalidValue)
/* ----- Reporting an Array of Integers (SimpleArrayReport) ----- */
/*
* Determine the buffer size for a SimpleArrayReport.
*
* int nValues - number of values to be reported
*/
#define SIMPLEARRAY_BUFSIZE(nValues) \
((((nValues)/IOR_VALUES_PER_ELEMENT) + (((nValues) % IOR_VALUES_PER_ELEMENT) ? 1:0)) \
* sizeof(IOReportElement))
/*
* Initialize a buffer for use as a SimpleArrayReport.
*
* int nValues - number of elements to be reported
* void* buf - ptr to SIMPLEARRAY_BUFSIZE(nValues) bytes
* size_t bufSize - sanity check of buffer's size
* uint64_t providerID - registry Entry ID of the reporting service
* uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
* IOReportCategories categories - categories of this channel
*
* If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT().
* If that returns, the buffer is left full of '&'.
*/
#define SIMPLEARRAY_INIT(nValues, buf, bufSize, providerID, channelID, cats) \
do { \
memset((buf), '&', (bufSize)); \
IOSimpleArrayReportValues *__rep; \
IOReportElement *__elem; \
uint32_t __nElems = (((nValues) / IOR_VALUES_PER_ELEMENT) + \
(((nValues) % IOR_VALUES_PER_ELEMENT) ? 1 : 0)); \
if ((bufSize) >= SIMPLEARRAY_BUFSIZE(nValues)) { \
for (unsigned __no = 0; __no < __nElems; __no++) { \
__elem = &(((IOReportElement *)(buf))[__no]); \
__rep = (IOSimpleArrayReportValues *) &(__elem->values); \
__elem->provider_id = (providerID); \
__elem->channel_id = (channelID); \
__elem->channel_type.report_format = kIOReportFormatSimpleArray; \
__elem->channel_type.reserved = 0; \
__elem->channel_type.categories = (cats); \
__elem->channel_type.nelements = (__nElems); \
__elem->channel_type.element_idx = __no; \
__elem->timestamp = 0; \
__rep->simple_values[0] = kIOReportInvalidIntValue; \
__rep->simple_values[1] = kIOReportInvalidIntValue; \
__rep->simple_values[2] = kIOReportInvalidIntValue; \
__rep->simple_values[3] = kIOReportInvalidIntValue; \
} \
} \
else { \
IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
} \
} while(0)
/* SimpleArrayReport helpers */
#define __SA_FINDREP(array_buf, idx) \
IOSimpleArrayReportValues *__rep; \
IOReportElement *__elem; \
unsigned __elemIdx = (idx) / IOR_VALUES_PER_ELEMENT; \
unsigned __valueIdx = (idx) % IOR_VALUES_PER_ELEMENT; \
__elem = &(((IOReportElement *)(array_buf))[0]); \
if (__elemIdx < __elem->channel_type.nelements) { \
__elem = &(((IOReportElement *)(array_buf))[__elemIdx]); \
__rep = (IOSimpleArrayReportValues *) &(__elem->values); \
#define __SA_MAXINDEX(array_buf) \
((((IOReportElement*)(array_buf))->channel_type.nelements) \
* IOR_VALUES_PER_ELEMENT) - 1
/*
* Set a value at a specified index in a SimpleArrayReport.
*
* void* array_bufbuf - ptr to memory initialized by SIMPLEARRAY_INIT()
* unsigned idx - array index, out of bounds -> no-op
* uint64_t newValue - new value to be stored at array[idx]
*/
#define SIMPLEARRAY_SETVALUE(array_buf, idx, newValue) \
do { \
__SA_FINDREP((array_buf), (idx)) \
__rep->simple_values[__valueIdx] = (newValue); \
} \
} while(0)
/*
* Increment an array value within a SimpleArrayReport.
*
* void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
* unsigned idx - array index to increment, out of bounds -> no-op
* int64_t value - amount by which to increment array[idx]
*/
#define SIMPLEARRAY_INCREMENTVALUE(array_buf, idx, value) \
do { \
__SA_FINDREP((array_buf), (idx)) \
if (os_add_overflow(__rep->simple_values[__valueIdx], (value), &__rep->simple_values[__valueIdx])) { \
__rep->simple_values[__valueIdx] = INT64_MAX; \
} \
} \
} while(0)
/*
* Prepare a SimpleArrayReport for
* IOService::updateReport(kIOReportCopyChannelData...)
*
* void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
* void* ptr2cpy - filled in with pointer to buffer to be copied out
* size_t size2cpy - filled in with the size of the buffer to copy out
*/
#define SIMPLEARRAY_UPDATEPREP(array_buf, ptr2cpy, size2cpy) \
do { \
IOReportElement *__elem; \
__elem = &(((IOReportElement *)(array_buf))[0]); \
(ptr2cpy) = (void *) (array_buf); \
(size2cpy) = __elem->channel_type.nelements * sizeof(IOReportElement); \
} while(0)
/*
* Update the result field received as a parameter for kIOReportGetDimensions &
* kIOReportCopyChannelData actions.
*
* void* array_buf - memory initialized by SIMPLEARRAY_INIT()
* IOReportConfigureAction action - configure/updateReport() 'action'
* void* result - configure/updateReport() 'result'
*/
#define SIMPLEARRAY_UPDATERES(array_buf, action, result) \
do { \
IOReportElement *__elem; \
int *__nElements = (int *)(result); \
__elem = &(((IOReportElement *)(array_buf))[0]); \
if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
if (os_add_overflow(*__nElements, __elem->channel_type.nelements, __nElements)) { \
*__nElements = INT_MAX; \
} \
} \
} while (0)
/*
* Get the 64-bit channel ID of a SimpleArrayReport.
*
* void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
*/
#define SIMPLEARRAY_GETCHID(array_buf) \
(((IOReportElement *)(array_buf))->channel_id)
/*
* Get the IOReportChannelType of a SimpleArrayReport.
*
* void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
*/
#define SIMPLEARRAY_GETCHTYPE(array_buf) \
(*(uint64_t*)&(((IOReportElement *)(array_buf))->channel_type))
/*
* Get a value from a SimpleArrayReport.
*
* void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
* unsigned idx - index of the value, out of bounds -> kIOReportInvalidValue
*/
#define SIMPLEARRAY_GETVALUE(array_buf, idx) \
(((idx) > __SA_MAXINDEX(array_buf) || (idx) < 0) ? kIOReportInvalidIntValue : \
((IOSimpleArrayReportValues*)&( \
((IOReportElement*)(array_buf))[(idx) / IOR_VALUES_PER_ELEMENT].values)) \
->simple_values[(idx) % IOR_VALUES_PER_ELEMENT])
/* ----- Histogram Reporting (HistogramReport) ----- */
// Internal struct for HistogramReport
typedef struct {
int bucketWidth;
IOReportElement elem[]; // Array of elements
} IOHistReportInfo;
/*
* Determine the size required for a HistogramReport buffer.
*
* int nbuckets - number of buckets in the histogram
*/
#define HISTREPORT_BUFSIZE(nbuckets) \
(sizeof(IOHistReportInfo) + ((nbuckets) * sizeof(IOReportElement)))
/*
* Initialize a HistogramReport buffer. Supports only linear scale histogram.
*
* uint16_t nbuckets - number of buckets data is combined into
* uint32_t bucketWidth - size of each bucket
* void* buffer - ptr to HISTREPORT_BUFSIZE(nbuckets) bytes
* size_t bufSize - sanity check of buffer's size
* uint64_t providerID - registry Entry ID of the reporting service
* uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
* IOReportCategories categories - categories of this channel
*
* If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT.
* If that returns, the buffer is left full of '&'.
*/
#define HISTREPORT_INIT(nbuckets, bktSize, buf, bufSize, providerID, channelID, cats) \
do { \
memset((buf), '&', (bufSize)); \
IOHistReportInfo *__info = (IOHistReportInfo *)(buf); \
IOReportElement *__elem; \
IOHistogramReportValues *__rep; \
if ((bufSize) >= HISTREPORT_BUFSIZE(nbuckets)) { \
__info->bucketWidth = (bktSize); \
for (uint16_t __no = 0; __no < (nbuckets); __no++) { \
__elem = &(__info->elem[__no]); \
__rep = (IOHistogramReportValues *) &(__elem->values); \
__elem->provider_id = (providerID); \
__elem->channel_id = (channelID); \
__elem->channel_type.report_format = kIOReportFormatHistogram; \
__elem->channel_type.reserved = 0; \
__elem->channel_type.categories = (cats); \
__elem->channel_type.nelements = (nbuckets); \
__elem->channel_type.element_idx = __no; \
__elem->timestamp = 0; \
memset(__rep, '\0', sizeof(IOHistogramReportValues)); \
} \
} \
else { \
IOREPORT_ABORT("bufSize is smaller than the required size\n"); \
} \
} while (0)
/*
* Update histogram with a new value.
*
*
* void* hist_buf - pointer to memory initialized by HISTREPORT_INIT()
* int64_t value - new value to add to the histogram
*/
#define HISTREPORT_TALLYVALUE(hist_buf, value) \
do { \
IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
IOReportElement *__elem; \
IOHistogramReportValues *__rep; \
for (unsigned __no = 0; __no < __info->elem[0].channel_type.nelements; __no++) { \
if ((value) <= __info->bucketWidth * (__no+1)) { \
__elem = &(__info->elem[__no]); \
__rep = (IOHistogramReportValues *) &(__elem->values); \
if (__rep->bucket_hits == 0) { \
__rep->bucket_min = __rep->bucket_max = (value); \
} \
else if ((value) < __rep->bucket_min) { \
__rep->bucket_min = (value); \
} \
else if ((value) > __rep->bucket_max) { \
__rep->bucket_max = (value); \
} \
int64_t __sum = 0; \
if (os_add_overflow(__rep->bucket_sum, (value), &__sum)) { \
__rep->bucket_sum = INT64_MAX; \
} else { \
__rep->bucket_sum = __sum; \
} \
__rep->bucket_hits++; \
break; \
} \
} \
} while (0)
/*
* Prepare a HistogramReport for
* IOService::updateReport(kIOReportCopyChannelData...)
*
* void* array_buf - ptr to memory initialized by HISTREPORT_INIT()
* void* ptr2cpy - filled in with pointer to buffer to be copied out
* size_t size2cpy - filled in with the size of the buffer to copy out
*/
#define HISTREPORT_UPDATEPREP(hist_buf, ptr2cpy, size2cpy) \
do { \
IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
(size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement); \
(ptr2cpy) = (void *) &__info->elem[0]; \
} while(0)
/*
* Update the result field received as a parameter for kIOReportGetDimensions &
* kIOReportCopyChannelData actions.
*
* void* array_buf - memory initialized by HISTREPORT_INIT()
* IOReportConfigureAction action - configure/updateReport() 'action'
* void* result - configure/updateReport() 'result'
*/
#define HISTREPORT_UPDATERES(hist_buf, action, result) \
do { \
IOHistReportInfo *__info = (IOHistReportInfo *)(hist_buf); \
int *__nElements = (int *)(result); \
if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
if (os_add_overflow(*__nElements, __info->elem[0].channel_type.nelements, __nElements)) { \
*__nElements = INT_MAX; \
} \
} \
} while (0)
/*
* Get the 64-bit channel ID of a HistogramReport.
*
* void* hist_buf - ptr to memory initialized by HISTREPORT_INIT()
*/
#define HISTREPORT_GETCHID(hist_buf) \
(((IOHistReportInfo *)(hist_buf))->elem[0].channel_id)
/*
* Get the IOReportChannelType of a HistogramReport.
*
* void* hist_buf - ptr to memory initialized by HISTREPORT_INIT()
*/
#define HISTREPORT_GETCHTYPE(hist_buf) \
(*(uint64_t*)&(((IOHistReportInfo *)(hist_buf))->elem[0].channel_type))
#ifdef __cplusplus
}
#endif
#endif // _IOREPORT_MACROS_H_