/* * 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 #include #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_