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