]> git.saurik.com Git - apple/xnu.git/blob - iokit/IOKit/IOReportMacros.h
xnu-2422.90.20.tar.gz
[apple/xnu.git] / iokit / IOKit / IOReportMacros.h
1 /*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 2012 Apple Computer, Inc. All Rights Reserved.
5 *
6 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. The rights granted to you under the License
12 * may not be used to create, or enable the creation or redistribution of,
13 * unlawful or unlicensed copies of an Apple operating system, or to
14 * circumvent, violate, or enable the circumvention or violation of, any
15 * terms of an Apple operating system software license agreement.
16 *
17 * Please obtain a copy of the License at
18 * http://www.opensource.apple.com/apsl/ and read it before using this file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 */
30
31 #ifndef _IOREPORT_MACROS_H_
32 #define _IOREPORT_MACROS_H_
33
34 #include "IOReportTypes.h"
35
36 #ifdef __cplusplus
37 extern "C" {
38 #endif
39
40 /*
41 Background
42
43 These macros allow non-I/O Kit software to generate IOReporting
44 reports. Clients must prevent concurrent access to any given
45 report buffer from multiple threads.
46
47 While these macros allow non-I/O Kit software to participate
48 in IOReporting, an IOService instance must lend its driver ID,
49 respond to the appropriate IOService overrides, and shuttle
50 data back and forth. In some cases, it may be useful to have
51 the I/O Kit driver initialize the report buffer with the
52 appropriate macro.
53 */
54
55 /*
56 * Returns the buffer size required for a Simple report.
57 */
58 #define SIMPLEREPORT_BUFSIZE (sizeof(IOReportElement))
59
60 /*
61 * Initialize a buffer to hold a Simple (integer) report.
62 *
63 * void* buffer - ptr to SIMPLEREPORT_BUFSIZE bytes
64 * size_t bufSize - sanity check of buffer's size
65 * uint64_t providerID - registry Entry ID of the reporting service
66 * uint64_t channelID - the report's channel ID
67 * IOReportCategories categories - categories of this channel
68 *
69 * If the buffer is not of sufficient size, the macro performs a
70 * null pointer reference to trigger a segfault. Then, the buffer is
71 * filled with 0xbadcafe.
72 */
73 #define SIMPLEREPORT_INIT(buffer, bufSize, providerID, channelID, cats) \
74 do { \
75 IOReportElement *__elem = (IOReportElement *)(buffer); \
76 IOSimpleReportValues *__vals; \
77 if ((bufSize) >= SIMPLEREPORT_BUFSIZE) { \
78 __elem->channel_id = (channelID); \
79 __elem->provider_id = (providerID); \
80 __elem->channel_type.report_format = kIOReportFormatSimple; \
81 __elem->channel_type.reserved = 0; \
82 __elem->channel_type.categories = (cats); \
83 __elem->channel_type.nelements = 1; \
84 __elem->channel_type.element_idx = 0; \
85 __elem->timestamp = 0; \
86 __vals = (IOSimpleReportValues*)&__elem->values; \
87 __vals->simple_value = kIOReportInvalidValue; \
88 } \
89 else { \
90 uint32_t *__nptr = NULL; \
91 *__nptr = 1; \
92 POLLUTE_BUF((buffer), (bufSize)); \
93 } \
94 } while(0)
95
96
97 /*
98 * Sets the SimpleReport channel to a new value.
99 *
100 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
101 * uint64_t new_value - new value for the channel
102 */
103 #define SIMPLEREPORT_SETVALUE(simp_buf, new_value) \
104 do { \
105 IOReportElement *__elem = (IOReportElement *)(simp_buf); \
106 IOSimpleReportValues *__vals; \
107 __vals = (IOSimpleReportValues*)&__elem->values; \
108 __vals->simple_value = (new_value); \
109 } while(0)
110
111 /*
112 * Prepare simple report buffer for
113 * IOService::updateReport(kIOReportCopyChannelData...)
114 *
115 * void* simp_buf - Ptr to memory updated by SIMPLEREPORT_SETVALUE()
116 * void* ptr2cpy - On return, 'ptr2cpy' points to the memory that needs to be
117 * copied for kIOReportCopyChannelData.
118 * size_t size2cpy - On return, 'size2cpy' is set to the size of the report
119 * data that needs to be copied for kIOReportCopyChannelData.
120 */
121 #define SIMPLEREPORT_UPDATEPREP(simp_buf, ptr2cpy, size2cpy) \
122 do { \
123 (ptr2cpy) = (simp_buf); \
124 (size2cpy) = sizeof(IOReportElement); \
125 } while(0)
126
127
128 /*
129 * Updates the result field received as a parameter for
130 * kIOReportGetDimensions & kIOReportCopyChannelData actions.
131 *
132 * IOReportConfigureAction action - configure/updateReport() 'action' param
133 * void* result - configure/updateReport() 'result' param
134 */
135
136 #define SIMPLEREPORT_UPDATERES(action, result) \
137 do { \
138 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
139 int *__nElements = (int *)(result); \
140 *__nElements += 1; \
141 } \
142 } while (0)
143
144
145
146 /*
147 * Returns the channel id from the buffer previously initialized by
148 * SIMPLEREPORT_INIT().
149 *
150 * void* simp_buf - ptr to memory initialized by SIMPLEREPORT_INIT()
151 */
152
153 #define SIMPLEREPORT_GETCHID(simp_buf) \
154 (((IOReportElement *)(simp_buf))->channel_id); \
155
156
157
158 // Internal struct for State report buffer
159 typedef struct {
160 uint16_t curr_state;
161 uint64_t update_ts;
162 IOReportElement elem[]; // Array of elements
163 } IOStateReportInfo;
164
165 /*
166 * Returns the size required to be allocated for using STATEREPORT_*()
167 *
168 * int nstates - number of states for the intended channel
169 */
170 #define STATEREPORT_BUFSIZE(nstates) \
171 (sizeof(IOStateReportInfo) + (nstates) * sizeof(IOReportElement))
172
173
174 /*
175 * Initializes a buffer so it can be used with STATEREPORT_*().
176 *
177 * int nstates - number of states to be reported
178 * void* buffer - ptr to STATEREPORT_BUFSIZE(nstates) bytes
179 * size_t bufSize - sanity check of buffer's size
180 * uint64_t providerID - registry Entry ID of the reporting service
181 * uint64_t channelID - ID of this channel, see IOREPORT_MAKEID()
182 * IOReportCategories categories - categories of this channel
183 *
184 * If the buffer is not of sufficient size, the macro performs a
185 * null pointer reference to trigger a segfault. Then, the buffer is
186 * filled with 0xbadcafe.
187 */
188 #define STATEREPORT_INIT(nstates, buf, bufSize, providerID, channelID, cats) \
189 do { \
190 IOStateReportInfo *__info = (IOStateReportInfo *)(buf); \
191 IOStateReportValues *__rep; \
192 IOReportElement *__elem; \
193 if ((bufSize) >= STATEREPORT_BUFSIZE(nstates)) { \
194 for (unsigned __no = 0; __no < (nstates); __no++) { \
195 __elem = &(__info->elem[__no]); \
196 __rep = (IOStateReportValues *) &(__elem->values); \
197 __elem->channel_id = (channelID); \
198 __elem->provider_id = (providerID); \
199 __elem->channel_type.report_format = kIOReportFormatState; \
200 __elem->channel_type.reserved = 0; \
201 __elem->channel_type.categories = (cats); \
202 __elem->channel_type.nelements = (nstates); \
203 __elem->channel_type.element_idx = __no; \
204 __elem->timestamp = 0; \
205 __rep->state_id = __no; \
206 __rep->intransitions = 0; \
207 __rep->upticks = 0; \
208 } \
209 __info->curr_state = 0; \
210 __info->update_ts = 0; \
211 } \
212 else { \
213 int *__nptr = NULL; \
214 *__nptr = 1; \
215 POLLUTE_BUF((buf), (bufSize)); \
216 } \
217 } while(0)
218
219 /*
220 * Initializes the state id field of a state with the specified value. By
221 * default, STATEREPORT_INIT initializes the state id with the index of
222 * that state. This macro can be used to provide a more descriptive state id.
223 *
224 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
225 * unsigned stateIdx - index of the state, out of bounds -> no-op
226 * uint64_t stateID - new state id, see IOREPORT_MAKEID()
227 */
228 #define STATEREPORT_SETSTATEID(state_buf, stateIdx, stateID) \
229 do { \
230 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
231 IOStateReportValues *__rep; \
232 if ((stateIdx) < __info->elem[0].channel_type.nelements) { \
233 __rep = (IOStateReportValues*) &(__info->elem[(stateIdx)].values); \
234 __rep->state_id = (stateID); \
235 } \
236 } while (0)
237
238
239 /*
240 * Set the state of a State report.
241 *
242 * void* state_buf - pointer to memory initialized by STATEREPORT_INIT()
243 * unsigned newStateIdx - index of new state, out of bounds -> no-op
244 * uint64_t changeTime - time at which the transition occurred
245 */
246 #define STATEREPORT_SETSTATE(state_buf, newStateIdx, changeTime) \
247 do { \
248 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
249 IOStateReportValues *__rep; \
250 if ((newStateIdx) < __info->elem[0].channel_type.nelements ) { \
251 __rep = (IOStateReportValues*) &(__info->elem[__info->curr_state].values); \
252 if (__info->update_ts) \
253 __rep->upticks += (changeTime) - __info->update_ts; \
254 __info->elem[(newStateIdx)].timestamp = (changeTime); \
255 __rep = (IOStateReportValues*) &(__info->elem[(newStateIdx)].values); \
256 __rep->intransitions++; \
257 __info->curr_state = (newStateIdx); \
258 __info->update_ts = (changeTime); \
259 } \
260 } while(0)
261
262 /*
263 * Prepare StateReport for UpdateReport call
264 *
265 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
266 * uint64_t currentTime - current timestamp
267 * void* ptr2cpy - filled in with pointer to buffer to be copied out
268 * size_t size2cpy - filled in with the size of the buffer to copy out
269 */
270 #define STATEREPORT_UPDATEPREP(state_buf, currentTime, ptr2cpy, size2cpy) \
271 do { \
272 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
273 IOReportElement *__elem; \
274 IOStateReportValues *__state; \
275 (size2cpy) = __info->elem[0].channel_type.nelements * sizeof(IOReportElement); \
276 (ptr2cpy) = (void *) &__info->elem[0]; \
277 if (__info->update_ts) { \
278 __elem = &__info->elem[__info->curr_state]; \
279 __state = (IOStateReportValues *)&__elem->values; \
280 __elem->timestamp = (currentTime); \
281 __state->upticks += (currentTime) - __info->update_ts; \
282 __info->update_ts = (currentTime); \
283 } \
284 } while(0)
285
286 /*
287 * Updates the result field received as a parameter for kIOReportGetDimensions &
288 * kIOReportCopyChannelData actions.
289 *
290 * void* state_buf - memory initialized by STATEREPORT_INIT()
291 * IOReportConfigureAction action - configure/updateReport() 'action'
292 * void* result - configure/updateReport() 'result'
293 */
294
295 #define STATEREPORT_UPDATERES(state_buf, action, result) \
296 do { \
297 IOStateReportInfo *__info = (IOStateReportInfo *)(state_buf); \
298 IOReportElement *__elem; \
299 int *__nElements = (int *)(result); \
300 if (((action) == kIOReportGetDimensions) || ((action) == kIOReportCopyChannelData)) { \
301 __elem = &(__info->elem[0]); \
302 *__nElements += __elem->channel_type.nelements; \
303 } \
304 } while (0)
305
306
307
308 /*
309 * Returns the channel id from the buffer previously initialized by STATEREPORT_INIT().
310 *
311 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
312 */
313
314 #define STATEREPORT_GETCHID(state_buf) \
315 (((IOStateReportInfo *)(state_buf))->elem[0].channel_id)
316
317 /*
318 * Returns number of transitions occurred from the given state
319 *
320 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
321 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
322 *
323 */
324
325 #define STATEREPORT_GETTRANSITIONS(state_buf, stateIdx) \
326 (((stateIdx) < ((IOStateReportInfo *)(state_buf))->elem[0].channel_type.nelements) \
327 ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->intransitions \
328 : kIOReportInvalidValue)
329
330 /*
331 * Returns the total number of ticks spent in the given state.
332 *
333 * void* state_buf - ptr to memory initialized by STATEREPORT_INIT()
334 * unsigned stateIdx - index of state, out of bounds -> kIOReportInvalidValue
335 */
336
337 #define STATEREPORT_GETTICKS(state_buf, stateIdx) \
338 (((stateIdx) < ((IOStateReportInfo*)(state_buf))->elem[0].channel_type.nelements) \
339 ? ((IOStateReportValues*)&(((IOStateReportInfo*)(state_buf))->elem[(stateIdx)].values))->upticks \
340 : kIOReportInvalidValue)
341
342
343 #define POLLUTE_BUF(buf, bufSize) \
344 do { \
345 int __cnt = (bufSize)/sizeof(uint32_t); \
346 while (--__cnt >= 0) \
347 ((uint32_t*)(buf))[__cnt] = 0xbadcafe; \
348 } while (0)
349
350 #ifdef __cplusplus
351 }
352 #endif
353
354 #endif // _IOREPORT_MACROS_H_
355
356