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 | #include <string.h> |
34 | |
35 | #ifdef __cplusplus |
36 | extern "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) \ |
82 | do { \ |
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) \ |
112 | do { \ |
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) \ |
127 | do { \ |
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) \ |
147 | do { \ |
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) \ |
162 | do { \ |
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 |
203 | typedef 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 | * int 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) \ |
232 | do { \ |
233 | memset((buf), '&', (bufSize)); \ |
234 | IOStateReportInfo *__info = (IOStateReportInfo *)(buf); \ |
235 | IOStateReportValues *__rep; \ |
236 | IOReportElement *__elem; \ |
237 | if ((bufSize) >= STATEREPORT_BUFSIZE(nstates)) { \ |
238 | for (unsigned __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) \ |
272 | do { \ |
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) \ |
290 | do { \ |
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) \ |
315 | do { \ |
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) \ |
340 | do { \ |
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) \ |
418 | do { \ |
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) \ |
472 | do { \ |
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) \ |
486 | do { \ |
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) \ |
503 | do { \ |
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) \ |
521 | do { \ |
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 |
564 | typedef 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 | * int 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) \ |
592 | do { \ |
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 (unsigned __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) \ |
626 | do { \ |
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) \ |
660 | do { \ |
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) \ |
677 | do { \ |
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_ |
706 | |
707 | |
708 | |