1/*
2 * Copyright (c) 2012-2014 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
34#ifdef __cplusplus
35extern "C" {
36#endif
37
38#ifndef IOREPORT_ABORT
39#define IOREPORT_ABORT panic
40#endif
41
42/*
43    Background
44
45    These macros allow non-I/O Kit software to generate IOReporting
46    reports.  Clients must prevent concurrent access to any given
47    report buffer from multiple threads.
48
49    While these macros allow non-I/O Kit software to participate
50    in IOReporting, an IOService instance must lend its driver ID,
51    respond to the appropriate IOService overrides, and shuttle
52    data back and forth.  In some cases, it may be useful to have
53    the I/O Kit driver initialize the report buffer with the
54    appropriate macro.
55*/
56
57
58/* ----- Reporting Single Integers (SimpleReport) ----- */
59
60/*
61 * The buffer size required for a SimpleReport.
62 */
63
64#define SIMPLEREPORT_BUFSIZE   (sizeof(IOReportElement))
65
66
67/*
68 * Initialize a buffer to hold a SimpleReport.
69 *
70 *                  void* buffer - ptr to SIMPLEREPORT_BUFSIZE bytes
71 *                size_t bufSize - sanity check of buffer's size
72 *           uint64_t providerID - registry Entry ID of the reporting service
73 *            uint64_t channelID - the report's channel ID
74 * IOReportCategories categories - categories of this channel
75 *
76 * If the buffer is not of sufficient size, the macro calls IOREPORT_ABORT().
77 * If that returns, the buffer is filled with 0xbadcafe.
78 */
79
80#define SIMPLEREPORT_INIT(buffer, bufSize, providerID, channelID, cats)  \
81do {  \
82    IOReportElement     *__elem = (IOReportElement *)(buffer);  \
83    IOSimpleReportValues *__vals;  \
84    if ((bufSize) >= SIMPLEREPORT_BUFSIZE) {  \
85        __elem->channel_id = (channelID);  \
86        __elem->provider_id = (providerID);  \
87        __elem->channel_type.report_format = kIOReportFormatSimple;  \
88        __elem->channel_type.reserved = 0;  \
89        __elem->channel_type.categories = (cats);  \
90        __elem->channel_type.nelements = 1;  \
91        __elem->channel_type.element_idx = 0;  \
92        __elem->timestamp = 0;  \
93        __vals = (IOSimpleReportValues*)&__elem->values;  \
94        __vals->simple_value = kIOReportInvalidIntValue;  \
95    }  \
96    else {  \
97        IOREPORT_ABORT("bufSize is smaller than the required size\n");  \
98        __POLLUTE_BUF((buffer), (bufSize));  \
99    }  \
100} while(0)
101
102
103/*
104 * Set a SimpleReport to a new value.
105 *
106 *    void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
107 * int64_t new_value - new value for the report
108 */
109
110#define SIMPLEREPORT_SETVALUE(simp_buf, new_value)  \
111do {  \
112    IOReportElement *__elem = (IOReportElement *)(simp_buf);  \
113    IOSimpleReportValues *__vals;  \
114    __vals = (IOSimpleReportValues*)&__elem->values;  \
115    __vals->simple_value = (new_value);  \
116} while(0)
117
118
119/*
120 * Increment the value of a SimpleReport.
121 *
122 *    void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
123 * int64_t increment - amount by which to increment the value
124 */
125#define SIMPLEREPORT_INCREMENTVALUE(simp_buf, new_value)  \
126do {  \
127    IOReportElement *__elem = (IOReportElement *)(simp_buf);  \
128    IOSimpleReportValues *__vals;  \
129    __vals = (IOSimpleReportValues*)&__elem->values;  \
130    __vals->simple_value += (new_value);  \
131} while(0)
132
133
134/*
135 * Prepare a SimpleReport for
136 * IOService::updateReport(kIOReportCopyChannelData...)
137 *
138 * void* simp_buf  - Ptr to memory updated by SIMPLEREPORT_SETVALUE()
139 * void* ptr2cpy   - On return, 'ptr2cpy' points to the memory that needs to be
140 *                   copied for kIOReportCopyChannelData.
141 * size_t size2cpy - On return, 'size2cpy' is set to the size of the report
142 *                   data that needs to be copied for kIOReportCopyChannelData.
143 */
144
145#define SIMPLEREPORT_UPDATEPREP(simp_buf, ptr2cpy, size2cpy)  \
146do {  \
147    (ptr2cpy) = (simp_buf);  \
148    (size2cpy) = sizeof(IOReportElement);  \
149} while(0)
150
151
152/*
153 * Update the result field received as a parameter for
154 * kIOReportGetDimensions & kIOReportCopyChannelData actions.
155 *
156 * IOReportConfigureAction action - configure/updateReport() 'action' param
157 *                   void* result - configure/updateReport() 'result' param
158 */
159
160#define SIMPLEREPORT_UPDATERES(action, result)  \
161do {  \
162    if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) {  \
163        int *__nElements = (int *)(result);  \
164        *__nElements += 1;  \
165    }  \
166} while (0)
167
168
169/*
170 * Get the 64-bit channel ID of a SimpleReport.
171 *
172 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
173 */
174
175#define SIMPLEREPORT_GETCHID(simp_buf)  \
176    (((IOReportElement *)(simp_buf))->channel_id)
177
178/*
179 * Get the IOReportChannelType of a SimpleReport.
180 *
181 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
182 */
183
184#define SIMPLEREPORT_GETCHTYPE(simp_buf)  \
185    (*(uint64_t*)&(((IOReportElement *)(simp_buf))->channel_type))
186
187
188/*
189 * Get the integer value of a SimpleReport.
190 *
191 * void* simp_buf - memory initialized by SIMPLEREPORT_INIT()
192 */
193
194#define SIMPLEREPORT_GETVALUE(simp_buf)  \
195    (((IOSimpleReportValues*)&(((IOReportElement*)(simp_buf))->values))  \
196            ->simple_value)
197
198
199/* ----- State Machine Reporting (StateReport) ----- */
200
201// Internal struct for StateReport
202typedef struct {
203   uint16_t        curr_state;
204   uint64_t        update_ts;
205   IOReportElement elem[]; // Array of elements
206} IOStateReportInfo;
207
208/*
209 * Determine the size required for a StateReport buffer.
210 *
211 * int nstates - number of states to be reported
212 */
213#define STATEREPORT_BUFSIZE(nstates)  \
214    (sizeof(IOStateReportInfo) + (nstates) * sizeof(IOReportElement))
215
216
217/*
218 * Initialize a StateReport buffer.
219 *
220 *                   int nstates - number of states to be reported
221 *                  void* buffer - ptr to STATEREPORT_BUFSIZE(nstates) bytes
222 *                size_t bufSize - sanity check of buffer's size
223 *           uint64_t providerID - registry Entry ID of the reporting service
224 *            uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
225 * IOReportCategories categories - categories of this channel
226 *
227 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT.
228 * If that returns, the buffer is filled with 0xbadcafe.
229 */
230#define STATEREPORT_INIT(nstates, buf, bufSize, providerID, channelID, cats) \
231do {  \
232    IOStateReportInfo *__info = (IOStateReportInfo *)(buf);  \
233    IOStateReportValues *__rep;  \
234    IOReportElement     *__elem;  \
235    if ((bufSize) >= STATEREPORT_BUFSIZE(nstates)) {  \
236        for (unsigned __no = 0; __no < (nstates); __no++) {  \
237            __elem =  &(__info->elem[__no]);  \
238            __rep = (IOStateReportValues *) &(__elem->values);  \
239            __elem->channel_id = (channelID);  \
240            __elem->provider_id = (providerID);  \
241            __elem->channel_type.report_format = kIOReportFormatState;  \
242            __elem->channel_type.reserved = 0;  \
243            __elem->channel_type.categories = (cats);  \
244            __elem->channel_type.nelements = (nstates);  \
245            __elem->channel_type.element_idx = __no;  \
246            __elem->timestamp = 0;  \
247            __rep->state_id = __no;  \
248            __rep->intransitions = 0;  \
249            __rep->upticks = 0;  \
250        }  \
251        __info->curr_state = 0;  \
252        __info->update_ts = 0;  \
253    }  \
254    else {  \
255        IOREPORT_ABORT("bufSize is smaller than the required size\n");  \
256        __POLLUTE_BUF((buf), (bufSize));  \
257    }  \
258} while(0)
259
260/*
261 * Initialize the state id field of a state with the specified value.  By
262 * default, STATEREPORT_INIT() initializes the state IDs with the index of
263 * that state.  This macro can be used to provide a more descriptive state id.
264 *
265 *   void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
266 * unsigned stateIdx - index of the state, out of bounds -> no-op
267 *  uint64_t stateID - new state id, see IOREPORT_MAKEID()
268 */
269#define STATEREPORT_SETSTATEID(state_buf, stateIdx, stateID)  \
270do {  \
271    IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf);  \
272    IOStateReportValues *__rep;  \
273    if ((stateIdx) < __info->elem[0].channel_type.nelements) {  \
274        __rep = (IOStateReportValues*) &(__info->elem[(stateIdx)].values);  \
275        __rep->state_id = (stateID);  \
276    }  \
277} while (0)
278
279
280/*
281 * Set the state of a StateReport.
282 *
283 *      void* state_buf - pointer to memory initialized by STATEREPORT_INIT()
284 * unsigned newStateIdx - index of new state, out of bounds -> no-op
285 *  uint64_t changeTime - time at which the transition occurred
286 */
287#define STATEREPORT_SETSTATE(state_buf, newStateIdx, changeTime)  \
288do {  \
289    IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf);  \
290    IOStateReportValues *__rep;  \
291    if ((newStateIdx) < __info->elem[0].channel_type.nelements ) {  \
292        __rep = (IOStateReportValues*) &(__info->elem[__info->curr_state].values);  \
293        if (__info->update_ts)  \
294            __rep->upticks += (changeTime) - __info->update_ts;  \
295        __info->elem[(newStateIdx)].timestamp = (changeTime);  \
296        __rep = (IOStateReportValues*) &(__info->elem[(newStateIdx)].values);  \
297        __rep->intransitions++;  \
298        __info->curr_state = (newStateIdx);  \
299        __info->update_ts = (changeTime);  \
300    }  \
301} while(0)
302
303/*
304 * Prepare a StateReport for
305 * IOService::updateReport(kIOReportCopyChannelData...)
306 *
307 *      void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
308 * uint64_t currentTime - current timestamp
309 *        void* ptr2cpy - filled in with pointer to buffer to be copied out
310 *      size_t size2cpy - filled in with the size of the buffer to copy out
311 */
312#define STATEREPORT_UPDATEPREP(state_buf, currentTime, ptr2cpy, size2cpy)  \
313do {  \
314    IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf);  \
315    IOReportElement     *__elem;  \
316    IOStateReportValues *__state;  \
317    (size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement);  \
318    (ptr2cpy) =  (void *) &__info->elem[0];  \
319    if (__info->update_ts)  {  \
320        __elem = &__info->elem[__info->curr_state];  \
321        __state = (IOStateReportValues *)&__elem->values;  \
322        __elem->timestamp = (currentTime);  \
323        __state->upticks  += (currentTime) - __info->update_ts;  \
324        __info->update_ts = (currentTime);  \
325    }  \
326} while(0)
327
328/*
329 * Update the result field received as a parameter for kIOReportGetDimensions &
330 * kIOReportCopyChannelData actions.
331 *
332 *                void* state_buf - memory initialized by STATEREPORT_INIT()
333 * IOReportConfigureAction action - configure/updateReport() 'action'
334 *                   void* result - configure/updateReport() 'result'
335 */
336
337#define STATEREPORT_UPDATERES(state_buf, action, result)  \
338do {  \
339    IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf);  \
340    IOReportElement     *__elem;  \
341    int *__nElements = (int *)(result);  \
342    if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) {  \
343        __elem =  &(__info->elem[0]);  \
344        *__nElements += __elem->channel_type.nelements;  \
345    }  \
346} while (0)
347
348
349/*
350 * Get the 64-bit channel ID of a StateReport.
351 *
352 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
353 */
354#define STATEREPORT_GETCHID(state_buf)  \
355    (((IOStateReportInfo *)(state_buf))->elem[0].channel_id)
356
357/*
358 * Get the IOReportChannelType of a StateReport.
359 *
360 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
361 */
362#define STATEREPORT_GETCHTYPE(state_buf)  \
363    (*(uint64_t*)&(((IOStateReportInfo *)(state_buf))->elem[0].channel_type))
364
365/*
366 * Get the number of transitions into a given state.
367 *
368 *   void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
369 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
370 *
371 */
372#define STATEREPORT_GETTRANSITIONS(state_buf, stateIdx)  \
373    (((stateIdx) < ((IOStateReportInfo *)(state_buf))->elem[0].channel_type.nelements)  \
374        ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->intransitions  \
375        : kIOReportInvalidValue)
376
377/*
378 * Get the total number of ticks spent in a given state.
379 *
380 *   void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
381 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
382 */
383#define STATEREPORT_GETTICKS(state_buf, stateIdx)  \
384    (((stateIdx) < ((IOStateReportInfo*)(state_buf))->elem[0].channel_type.nelements)  \
385        ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->upticks  \
386        : kIOReportInvalidValue)
387
388
389/* ----- Reporting an Array of Integers (SimpleArrayReport) ----- */
390
391/*
392 * Determine the buffer size for a SimpleArrayReport.
393 *
394 * int nValues - number of values to be reported
395 */
396
397#define SIMPLEARRAY_BUFSIZE(nValues) \
398    ((((nValues)/IOR_VALUES_PER_ELEMENT) + (((nValues) % IOR_VALUES_PER_ELEMENT) ? 1:0)) \
399        * sizeof(IOReportElement))
400
401/*
402 * Initialize a buffer for use as a SimpleArrayReport.
403 *
404 *                   int nValues   - number of elements to be reported
405 *                     void* buf   - ptr to SIMPLEARRAY_BUFSIZE(nValues) bytes
406 *                size_t bufSize   - sanity check of buffer's size
407 *           uint64_t providerID   - registry Entry ID of the reporting service
408 *            uint64_t channelID   - ID of this channel, see IOREPORT_MAKEID()
409 * IOReportCategories categories   - categories of this channel
410 *
411 * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT()
412 * and, if that returns, fills the buffer with 0xbadcafe.
413 */
414
415#define SIMPLEARRAY_INIT(nValues, buf, bufSize, providerID, channelID, cats) \
416do {  \
417    IOSimpleArrayReportValues *__rep;  \
418    IOReportElement     *__elem;  \
419    uint32_t            __nElems = (((nValues) / IOR_VALUES_PER_ELEMENT) + \
420                                    (((nValues) % IOR_VALUES_PER_ELEMENT) ? 1 : 0)); \
421    if ((bufSize) >= SIMPLEARRAY_BUFSIZE(nValues)) {  \
422        for (unsigned __no = 0; __no < __nElems; __no++) {  \
423            __elem =  &(((IOReportElement *)(buf))[__no]);  \
424            __rep = (IOSimpleArrayReportValues *) &(__elem->values);  \
425            __elem->channel_id = (channelID);  \
426            __elem->provider_id = (providerID);  \
427            __elem->channel_type.report_format = kIOReportFormatSimpleArray;  \
428            __elem->channel_type.reserved = 0;  \
429            __elem->channel_type.categories = (cats);  \
430            __elem->channel_type.nelements = (__nElems);  \
431            __elem->channel_type.element_idx = __no;  \
432            __elem->timestamp = 0;  \
433            __rep->simple_values[0] = kIOReportInvalidIntValue;  \
434            __rep->simple_values[1] = kIOReportInvalidIntValue;  \
435            __rep->simple_values[2] = kIOReportInvalidIntValue;  \
436            __rep->simple_values[3] = kIOReportInvalidIntValue;  \
437        }  \
438    }  \
439    else {  \
440        IOREPORT_ABORT("bufSize is smaller than the required size\n");  \
441        __POLLUTE_BUF((buf), (bufSize));  \
442    }  \
443} while(0)
444
445
446/* SimpleArrayReport helpers */
447
448    #define __SA_FINDREP(array_buf, idx)  \
449        IOSimpleArrayReportValues *__rep;  \
450        IOReportElement     *__elem;  \
451        unsigned __elemIdx = (idx) / IOR_VALUES_PER_ELEMENT;  \
452        unsigned __valueIdx = (idx) % IOR_VALUES_PER_ELEMENT;  \
453        __elem = &(((IOReportElement *)(array_buf))[0]);  \
454        if (__elemIdx < __elem->channel_type.nelements)  { \
455            __elem = &(((IOReportElement *)(array_buf))[__elemIdx]);  \
456            __rep = (IOSimpleArrayReportValues *) &(__elem->values);  \
457
458    #define __SA_MAXINDEX(array_buf)  \
459        ((((IOReportElement*)(array_buf))->channel_type.nelements)  \
460            * IOR_VALUES_PER_ELEMENT) - 1
461
462/*
463 * Set a value at a specified index in a SimpleArrayReport.
464 *
465 *   void* array_bufbuf - ptr to memory initialized by SIMPLEARRAY_INIT()
466 *        unsigned idx  - array index, out of bounds -> no-op
467 *    uint64_t newValue - new value to be stored at array[idx]
468 */
469#define SIMPLEARRAY_SETVALUE(array_buf, idx, newValue) \
470do {  \
471    __SA_FINDREP((array_buf), (idx)) \
472        __rep->simple_values[__valueIdx] = (newValue);  \
473    } \
474} while(0)
475
476/*
477 * Increment an array value within a SimpleArrayReport.
478 *
479 *     void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
480 *       unsigned idx  - array index to increment, out of bounds -> no-op
481 *      int64_t value  - amount by which to increment array[idx]
482 */
483#define SIMPLEARRAY_INCREMENTVALUE(array_buf, idx, value)  \
484do {  \
485    __SA_FINDREP((array_buf), (idx)) \
486        __rep->simple_values[__valueIdx] += (value);  \
487    } \
488} while(0)
489
490
491/*
492 * Prepare a SimpleArrayReport for
493 * IOService::updateReport(kIOReportCopyChannelData...)
494 *
495 *      void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
496 *        void* ptr2cpy - filled in with pointer to buffer to be copied out
497 *      size_t size2cpy - filled in with the size of the buffer to copy out
498 */
499
500#define SIMPLEARRAY_UPDATEPREP(array_buf, ptr2cpy, size2cpy) \
501do {  \
502    IOReportElement     *__elem;  \
503    __elem = &(((IOReportElement *)(array_buf))[0]);  \
504    (ptr2cpy) =  (void *) (array_buf);  \
505    (size2cpy) = __elem->channel_type.nelements * sizeof(IOReportElement);  \
506} while(0)
507
508
509/*
510 * Update the result field received as a parameter for kIOReportGetDimensions &
511 * kIOReportCopyChannelData actions.
512 *
513 *                void* array_buf - memory initialized by SIMPLEARRAY_INIT()
514 * IOReportConfigureAction action - configure/updateReport() 'action'
515 *                   void* result - configure/updateReport() 'result'
516 */
517
518#define SIMPLEARRAY_UPDATERES(array_buf, action, result) \
519do {  \
520    IOReportElement     *__elem;  \
521    int *__nElements = (int *)(result);  \
522    __elem = &(((IOReportElement *)(array_buf))[0]);  \
523    if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) {  \
524        *__nElements += __elem->channel_type.nelements;  \
525    }  \
526} while (0)
527
528
529/*
530 * Get the 64-bit channel ID of a SimpleArrayReport.
531 *
532 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
533 */
534#define SIMPLEARRAY_GETCHID(array_buf)  \
535    (((IOReportElement *)(array_buf))->channel_id)
536
537
538/*
539 * Get the IOReportChannelType of a SimpleArrayReport.
540 *
541 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
542 */
543#define SIMPLEARRAY_GETCHTYPE(array_buf)  \
544    (*(uint64_t*)&(((IOReportElement *)(array_buf))->channel_type))
545
546/*
547 * Get a value from a SimpleArrayReport.
548 *
549 * void* array_buf - ptr to memory initialized by SIMPLEARRAY_INIT()
550 *   unsigned idx  - index of the value, out of bounds -> kIOReportInvalidValue
551 */
552#define SIMPLEARRAY_GETVALUE(array_buf, idx)  \
553    (((idx) > __SA_MAXINDEX(array_buf) || (idx) < 0) ? kIOReportInvalidIntValue :  \
554    ((IOSimpleArrayReportValues*)&(  \
555        ((IOReportElement*)(array_buf))[(idx) / IOR_VALUES_PER_ELEMENT].values))  \
556            ->simple_values[(idx) % IOR_VALUES_PER_ELEMENT])
557
558
559/* generic utilities */
560
561    #define __POLLUTE_BUF(buf, bufSize)  \
562    do {  \
563        int __cnt = (bufSize)/sizeof(uint32_t);  \
564        while (--__cnt >= 0)  \
565            ((uint32_t*)(buf))[__cnt] = 0xbadcafe;  \
566    } while (0)
567
568#ifdef __cplusplus
569}
570#endif
571
572#endif // _IOREPORT_MACROS_H_
573
574
575