]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2012-2020 Apple Computer, Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | #ifndef _IOREPORT_MACROS_H_ | |
30 | #define _IOREPORT_MACROS_H_ | |
31 | ||
32 | #include "IOReportTypes.h" | |
33 | #include <string.h> | |
34 | ||
35 | #ifdef __cplusplus | |
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 | * uint16_t nstates - number of states to be reported | |
222 | * void* buffer - ptr to STATEREPORT_BUFSIZE(nstates) bytes | |
223 | * size_t bufSize - sanity check of buffer's size | |
224 | * uint64_t providerID - registry Entry ID of the reporting service | |
225 | * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID() | |
226 | * IOReportCategories categories - categories of this channel | |
227 | * | |
228 | * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT. | |
229 | * If that returns, the buffer is left full of '&'. | |
230 | */ | |
231 | #define STATEREPORT_INIT(nstates, buf, bufSize, providerID, channelID, cats) \ | |
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 (uint16_t __no = 0; __no < (nstates); __no++) { \ | |
239 | __elem = &(__info->elem[__no]); \ | |
240 | __rep = (IOStateReportValues *) &(__elem->values); \ | |
241 | __elem->provider_id = (providerID); \ | |
242 | __elem->channel_id = (channelID); \ | |
243 | __elem->channel_type.report_format = kIOReportFormatState; \ | |
244 | __elem->channel_type.reserved = 0; \ | |
245 | __elem->channel_type.categories = (cats); \ | |
246 | __elem->channel_type.nelements = (nstates); \ | |
247 | __elem->channel_type.element_idx = __no; \ | |
248 | __elem->timestamp = 0; \ | |
249 | __rep->state_id = __no; \ | |
250 | __rep->intransitions = 0; \ | |
251 | __rep->upticks = 0; \ | |
252 | __rep->last_intransition = 0; \ | |
253 | } \ | |
254 | __info->curr_state = 0; \ | |
255 | __info->update_ts = 0; \ | |
256 | } \ | |
257 | else { \ | |
258 | IOREPORT_ABORT("bufSize is smaller than the required size\n"); \ | |
259 | } \ | |
260 | } while(0) | |
261 | ||
262 | /* | |
263 | * Initialize the state id field of a state with the specified value. By | |
264 | * default, STATEREPORT_INIT() initializes the state IDs with the index of | |
265 | * that state. This macro can be used to provide a more descriptive state id. | |
266 | * | |
267 | * void* state_buf - ptr to memory initialized by STATEREPORT_INIT() | |
268 | * unsigned stateIdx - index of the state, out of bounds -> no-op | |
269 | * uint64_t stateID - new state id, see IOREPORT_MAKEID() | |
270 | */ | |
271 | #define STATEREPORT_SETSTATEID(state_buf, stateIdx, stateID) \ | |
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 | * uint16_t nbuckets - number of buckets data is combined into | |
581 | * uint32_t bucketWidth - size of each bucket | |
582 | * void* buffer - ptr to HISTREPORT_BUFSIZE(nbuckets) bytes | |
583 | * size_t bufSize - sanity check of buffer's size | |
584 | * uint64_t providerID - registry Entry ID of the reporting service | |
585 | * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID() | |
586 | * IOReportCategories categories - categories of this channel | |
587 | * | |
588 | * If the buffer is not of sufficient size, the macro invokes IOREPORT_ABORT. | |
589 | * If that returns, the buffer is left full of '&'. | |
590 | */ | |
591 | #define HISTREPORT_INIT(nbuckets, bktSize, buf, bufSize, providerID, channelID, cats) \ | |
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 (uint16_t __no = 0; __no < (nbuckets); __no++) { \ | |
600 | __elem = &(__info->elem[__no]); \ | |
601 | __rep = (IOHistogramReportValues *) &(__elem->values); \ | |
602 | __elem->provider_id = (providerID); \ | |
603 | __elem->channel_id = (channelID); \ | |
604 | __elem->channel_type.report_format = kIOReportFormatHistogram; \ | |
605 | __elem->channel_type.reserved = 0; \ | |
606 | __elem->channel_type.categories = (cats); \ | |
607 | __elem->channel_type.nelements = (nbuckets); \ | |
608 | __elem->channel_type.element_idx = __no; \ | |
609 | __elem->timestamp = 0; \ | |
610 | memset(__rep, '\0', sizeof(IOHistogramReportValues)); \ | |
611 | } \ | |
612 | } \ | |
613 | else { \ | |
614 | IOREPORT_ABORT("bufSize is smaller than the required size\n"); \ | |
615 | } \ | |
616 | } while (0) | |
617 | ||
618 | /* | |
619 | * Update histogram with a new value. | |
620 | * | |
621 | * | |
622 | * void* hist_buf - pointer to memory initialized by HISTREPORT_INIT() | |
623 | * int64_t value - new value to add to the histogram | |
624 | */ | |
625 | #define HISTREPORT_TALLYVALUE(hist_buf, value) \ | |
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_ |