1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * CPU Performance Counter system calls and device driver. 28 * 29 * This module uses a combination of thread context operators, and 30 * thread-specific data to export CPU performance counters 31 * via both a system call and a driver interface. 32 * 33 * There are three access methods exported - the 'shared' device 34 * and the 'private' and 'agent' variants of the system call. 35 * 36 * The shared device treats the performance counter registers as 37 * a processor metric, regardless of the work scheduled on them. 38 * The private system call treats the performance counter registers 39 * as a property of a single lwp. This is achieved by using the 40 * thread context operators to virtualize the contents of the 41 * performance counter registers between lwps. 42 * 43 * The agent method is like the private method, except that it must 44 * be accessed via /proc's agent lwp to allow the counter context of 45 * other threads to be examined safely. 46 * 47 * The shared usage fundamentally conflicts with the agent and private usage; 48 * almost all of the complexity of the module is needed to allow these two 49 * models to co-exist in a reasonable way. 50 */ 51 52 #include <sys/types.h> 53 #include <sys/file.h> 54 #include <sys/errno.h> 55 #include <sys/open.h> 56 #include <sys/cred.h> 57 #include <sys/conf.h> 58 #include <sys/stat.h> 59 #include <sys/processor.h> 60 #include <sys/cpuvar.h> 61 #include <sys/disp.h> 62 #include <sys/kmem.h> 63 #include <sys/modctl.h> 64 #include <sys/ddi.h> 65 #include <sys/sunddi.h> 66 #include <sys/nvpair.h> 67 #include <sys/policy.h> 68 #include <sys/machsystm.h> 69 #include <sys/cpc_impl.h> 70 #include <sys/cpc_pcbe.h> 71 #include <sys/kcpc.h> 72 73 static int kcpc_copyin_set(kcpc_set_t **set, void *ubuf, size_t len); 74 static int kcpc_verify_set(kcpc_set_t *set); 75 static uint32_t kcpc_nvlist_npairs(nvlist_t *list); 76 77 /* 78 * Generic attributes supported regardless of processor. 79 */ 80 81 #define ATTRLIST "picnum" 82 #define SEPARATOR "," 83 84 /* 85 * System call to access CPU performance counters. 86 */ 87 static int 88 cpc(int cmd, id_t lwpid, void *udata1, void *udata2, void *udata3) 89 { 90 kthread_t *t; 91 int error; 92 int size; 93 const char *str; 94 int code; 95 96 /* 97 * This CPC syscall should only be loaded if it found a PCBE to use. 98 */ 99 ASSERT(pcbe_ops != NULL); 100 101 if (curproc->p_agenttp == curthread) { 102 /* 103 * Only if /proc is invoking this system call from 104 * the agent thread do we allow the caller to examine 105 * the contexts of other lwps in the process. And 106 * because we know we're the agent, we know we don't 107 * have to grab p_lock because no-one else can change 108 * the state of the process. 109 */ 110 if ((t = idtot(curproc, lwpid)) == NULL || t == curthread) 111 return (set_errno(ESRCH)); 112 ASSERT(t->t_tid == lwpid && ttolwp(t) != NULL); 113 } else 114 t = curthread; 115 116 if (t->t_cpc_set == NULL && (cmd == CPC_SAMPLE || cmd == CPC_RELE)) 117 return (set_errno(EINVAL)); 118 119 switch (cmd) { 120 case CPC_BIND: 121 /* 122 * udata1 = pointer to packed nvlist buffer 123 * udata2 = size of packed nvlist buffer 124 * udata3 = User addr to return error subcode in. 125 */ 126 127 rw_enter(&kcpc_cpuctx_lock, RW_READER); 128 if (kcpc_cpuctx || dtrace_cpc_in_use) { 129 rw_exit(&kcpc_cpuctx_lock); 130 return (set_errno(EAGAIN)); 131 } 132 133 if (kcpc_hw_lwp_hook() != 0) { 134 rw_exit(&kcpc_cpuctx_lock); 135 return (set_errno(EACCES)); 136 } 137 138 /* 139 * An LWP may only have one set bound to it at a time; if there 140 * is a set bound to this LWP already, we unbind it here. 141 */ 142 if (t->t_cpc_set != NULL) 143 (void) kcpc_unbind(t->t_cpc_set); 144 ASSERT(t->t_cpc_set == NULL); 145 146 if ((error = kcpc_copyin_set(&t->t_cpc_set, udata1, 147 (size_t)udata2)) != 0) { 148 rw_exit(&kcpc_cpuctx_lock); 149 return (set_errno(error)); 150 } 151 152 if ((error = kcpc_verify_set(t->t_cpc_set)) != 0) { 153 rw_exit(&kcpc_cpuctx_lock); 154 kcpc_free_set(t->t_cpc_set); 155 t->t_cpc_set = NULL; 156 if (copyout(&error, udata3, sizeof (error)) == -1) 157 return (set_errno(EFAULT)); 158 return (set_errno(EINVAL)); 159 } 160 161 if ((error = kcpc_bind_thread(t->t_cpc_set, t, &code)) != 0) { 162 rw_exit(&kcpc_cpuctx_lock); 163 kcpc_free_set(t->t_cpc_set); 164 t->t_cpc_set = NULL; 165 /* 166 * EINVAL and EACCES are the only errors with more 167 * specific subcodes. 168 */ 169 if ((error == EINVAL || error == EACCES) && 170 copyout(&code, udata3, sizeof (code)) == -1) 171 return (set_errno(EFAULT)); 172 return (set_errno(error)); 173 } 174 175 rw_exit(&kcpc_cpuctx_lock); 176 return (0); 177 case CPC_SAMPLE: 178 /* 179 * udata1 = pointer to user's buffer 180 * udata2 = pointer to user's hrtime 181 * udata3 = pointer to user's tick 182 */ 183 /* 184 * We only allow thread-bound sets to be sampled via the 185 * syscall, so if this set has a CPU-bound context, return an 186 * error. 187 */ 188 if (t->t_cpc_set->ks_ctx->kc_cpuid != -1) 189 return (set_errno(EINVAL)); 190 if ((error = kcpc_sample(t->t_cpc_set, udata1, udata2, 191 udata3)) != 0) 192 return (set_errno(error)); 193 194 return (0); 195 case CPC_PRESET: 196 case CPC_RESTART: 197 /* 198 * These are valid only if this lwp has a bound set. 199 */ 200 if (t->t_cpc_set == NULL) 201 return (set_errno(EINVAL)); 202 if (cmd == CPC_PRESET) { 203 /* 204 * The preset is shipped up to us from userland in two 205 * parts. This lets us handle 64-bit values from 32-bit 206 * and 64-bit applications in the same manner. 207 * 208 * udata1 = index of request to preset 209 * udata2 = new 64-bit preset (most sig. 32 bits) 210 * udata3 = new 64-bit preset (least sig. 32 bits) 211 */ 212 if ((error = kcpc_preset(t->t_cpc_set, (intptr_t)udata1, 213 ((uint64_t)(uintptr_t)udata2 << 32ULL) | 214 (uint64_t)(uintptr_t)udata3)) != 0) 215 return (set_errno(error)); 216 } else { 217 /* 218 * udata[1-3] = unused 219 */ 220 if ((error = kcpc_restart(t->t_cpc_set)) != 0) 221 return (set_errno(error)); 222 } 223 return (0); 224 case CPC_ENABLE: 225 case CPC_DISABLE: 226 udata1 = 0; 227 /*FALLTHROUGH*/ 228 case CPC_USR_EVENTS: 229 case CPC_SYS_EVENTS: 230 if (t != curthread || t->t_cpc_set == NULL) 231 return (set_errno(EINVAL)); 232 /* 233 * Provided for backwards compatibility with CPCv1. 234 * 235 * Stop the counters and record the current counts. Use the 236 * counts as the preset to rebind a new set with the requests 237 * reconfigured as requested. 238 * 239 * udata1: 1 == enable; 0 == disable 240 * udata{2,3}: unused 241 */ 242 rw_enter(&kcpc_cpuctx_lock, RW_READER); 243 if ((error = kcpc_enable(t, 244 cmd, (int)(uintptr_t)udata1)) != 0) { 245 rw_exit(&kcpc_cpuctx_lock); 246 return (set_errno(error)); 247 } 248 rw_exit(&kcpc_cpuctx_lock); 249 return (0); 250 case CPC_NPIC: 251 return (cpc_ncounters); 252 case CPC_CAPS: 253 return (pcbe_ops->pcbe_caps); 254 case CPC_EVLIST_SIZE: 255 case CPC_LIST_EVENTS: 256 /* 257 * udata1 = pointer to user's int or buffer 258 * udata2 = picnum 259 * udata3 = unused 260 */ 261 if ((uintptr_t)udata2 >= cpc_ncounters) 262 return (set_errno(EINVAL)); 263 264 size = strlen( 265 pcbe_ops->pcbe_list_events((uintptr_t)udata2)) + 1; 266 267 if (cmd == CPC_EVLIST_SIZE) { 268 if (suword32(udata1, size) == -1) 269 return (set_errno(EFAULT)); 270 } else { 271 if (copyout( 272 pcbe_ops->pcbe_list_events((uintptr_t)udata2), 273 udata1, size) == -1) 274 return (set_errno(EFAULT)); 275 } 276 return (0); 277 case CPC_ATTRLIST_SIZE: 278 case CPC_LIST_ATTRS: 279 /* 280 * udata1 = pointer to user's int or buffer 281 * udata2 = unused 282 * udata3 = unused 283 * 284 * attrlist size is length of PCBE-supported attributes, plus 285 * room for "picnum\0" plus an optional ',' separator char. 286 */ 287 str = pcbe_ops->pcbe_list_attrs(); 288 size = strlen(str) + sizeof (SEPARATOR ATTRLIST) + 1; 289 if (str[0] != '\0') 290 /* 291 * A ',' separator character is necessary. 292 */ 293 size += 1; 294 295 if (cmd == CPC_ATTRLIST_SIZE) { 296 if (suword32(udata1, size) == -1) 297 return (set_errno(EFAULT)); 298 } else { 299 /* 300 * Copyout the PCBE attributes, and then append the 301 * generic attribute list (with separator if necessary). 302 */ 303 if (copyout(str, udata1, strlen(str)) == -1) 304 return (set_errno(EFAULT)); 305 if (str[0] != '\0') { 306 if (copyout(SEPARATOR ATTRLIST, 307 ((char *)udata1) + strlen(str), 308 strlen(SEPARATOR ATTRLIST) + 1) 309 == -1) 310 return (set_errno(EFAULT)); 311 } else 312 if (copyout(ATTRLIST, 313 (char *)udata1 + strlen(str), 314 strlen(ATTRLIST) + 1) == -1) 315 return (set_errno(EFAULT)); 316 } 317 return (0); 318 case CPC_IMPL_NAME: 319 case CPC_CPUREF: 320 /* 321 * udata1 = pointer to user's buffer 322 * udata2 = unused 323 * udata3 = unused 324 */ 325 if (cmd == CPC_IMPL_NAME) { 326 str = pcbe_ops->pcbe_impl_name(); 327 ASSERT(strlen(str) < CPC_MAX_IMPL_NAME); 328 } else { 329 str = pcbe_ops->pcbe_cpuref(); 330 ASSERT(strlen(str) < CPC_MAX_CPUREF); 331 } 332 333 if (copyout(str, udata1, strlen(str) + 1) != 0) 334 return (set_errno(EFAULT)); 335 return (0); 336 case CPC_INVALIDATE: 337 kcpc_invalidate(t); 338 return (0); 339 case CPC_RELE: 340 if ((error = kcpc_unbind(t->t_cpc_set)) != 0) 341 return (set_errno(error)); 342 return (0); 343 default: 344 return (set_errno(EINVAL)); 345 } 346 } 347 348 /* 349 * The 'shared' device allows direct access to the 350 * performance counter control register of the current CPU. 351 * The major difference between the contexts created here and those 352 * above is that the context handlers are -not- installed, thus 353 * no context switching behaviour occurs. 354 * 355 * Because they manipulate per-cpu state, these ioctls can 356 * only be invoked from a bound lwp, by a caller with the cpc_cpu privilege 357 * who can open the relevant entry in /devices (the act of holding it open 358 * causes other uses of the counters to be suspended). 359 * 360 * Note that for correct results, the caller -must- ensure that 361 * all existing per-lwp contexts are either inactive or marked invalid; 362 * that's what the open routine does. 363 */ 364 /*ARGSUSED*/ 365 static int 366 kcpc_ioctl(dev_t dev, int cmd, intptr_t data, int flags, cred_t *cr, int *rvp) 367 { 368 kthread_t *t = curthread; 369 processorid_t cpuid; 370 void *udata1 = NULL; 371 void *udata2 = NULL; 372 void *udata3 = NULL; 373 int error; 374 int code; 375 376 STRUCT_DECL(__cpc_args, args); 377 378 STRUCT_INIT(args, flags); 379 380 if (curthread->t_bind_cpu != getminor(dev)) 381 return (EAGAIN); /* someone unbound it? */ 382 383 cpuid = getminor(dev); 384 385 if (cmd == CPCIO_BIND || cmd == CPCIO_SAMPLE) { 386 if (copyin((void *)data, STRUCT_BUF(args), 387 STRUCT_SIZE(args)) == -1) 388 return (EFAULT); 389 390 udata1 = STRUCT_FGETP(args, udata1); 391 udata2 = STRUCT_FGETP(args, udata2); 392 udata3 = STRUCT_FGETP(args, udata3); 393 } 394 395 switch (cmd) { 396 case CPCIO_BIND: 397 /* 398 * udata1 = pointer to packed nvlist buffer 399 * udata2 = size of packed nvlist buffer 400 * udata3 = User addr to return error subcode in. 401 */ 402 if (t->t_cpc_set != NULL) { 403 (void) kcpc_unbind(t->t_cpc_set); 404 ASSERT(t->t_cpc_set == NULL); 405 } 406 407 if ((error = kcpc_copyin_set(&t->t_cpc_set, udata1, 408 (size_t)udata2)) != 0) { 409 return (error); 410 } 411 412 if ((error = kcpc_verify_set(t->t_cpc_set)) != 0) { 413 kcpc_free_set(t->t_cpc_set); 414 t->t_cpc_set = NULL; 415 if (copyout(&error, udata3, sizeof (error)) == -1) 416 return (EFAULT); 417 return (EINVAL); 418 } 419 420 if ((error = kcpc_bind_cpu(t->t_cpc_set, cpuid, &code)) != 0) { 421 kcpc_free_set(t->t_cpc_set); 422 t->t_cpc_set = NULL; 423 /* 424 * Subcodes are only returned for EINVAL and EACCESS. 425 */ 426 if ((error == EINVAL || error == EACCES) && 427 copyout(&code, udata3, sizeof (code)) == -1) 428 return (EFAULT); 429 return (error); 430 } 431 432 return (0); 433 case CPCIO_SAMPLE: 434 /* 435 * udata1 = pointer to user's buffer 436 * udata2 = pointer to user's hrtime 437 * udata3 = pointer to user's tick 438 */ 439 /* 440 * Only CPU-bound sets may be sampled via the ioctl(). If this 441 * set has no CPU-bound context, return an error. 442 */ 443 if (t->t_cpc_set == NULL) 444 return (EINVAL); 445 if ((error = kcpc_sample(t->t_cpc_set, udata1, udata2, 446 udata3)) != 0) 447 return (error); 448 return (0); 449 case CPCIO_RELE: 450 if (t->t_cpc_set == NULL) 451 return (EINVAL); 452 return (kcpc_unbind(t->t_cpc_set)); 453 default: 454 return (EINVAL); 455 } 456 } 457 458 /* 459 * The device supports multiple opens, but only one open 460 * is allowed per processor. This is to enable multiple 461 * instances of tools looking at different processors. 462 */ 463 #define KCPC_MINOR_SHARED ((minor_t)0x3fffful) 464 465 static ulong_t *kcpc_cpumap; /* bitmap of cpus */ 466 467 /*ARGSUSED1*/ 468 static int 469 kcpc_open(dev_t *dev, int flags, int otyp, cred_t *cr) 470 { 471 processorid_t cpuid; 472 int error; 473 474 ASSERT(pcbe_ops != NULL); 475 476 if ((error = secpolicy_cpc_cpu(cr)) != 0) 477 return (error); 478 if (getminor(*dev) != KCPC_MINOR_SHARED) 479 return (ENXIO); 480 if ((cpuid = curthread->t_bind_cpu) == PBIND_NONE) 481 return (EINVAL); 482 if (cpuid > max_cpuid) 483 return (EINVAL); 484 485 rw_enter(&kcpc_cpuctx_lock, RW_WRITER); 486 if (++kcpc_cpuctx == 1) { 487 ASSERT(kcpc_cpumap == NULL); 488 489 /* 490 * Bail out if DTrace is already using the counters. 491 */ 492 if (dtrace_cpc_in_use) { 493 kcpc_cpuctx--; 494 rw_exit(&kcpc_cpuctx_lock); 495 return (EAGAIN); 496 } 497 kcpc_cpumap = kmem_zalloc(BT_SIZEOFMAP(max_cpuid + 1), 498 KM_SLEEP); 499 /* 500 * When this device is open for processor-based contexts, 501 * no further lwp-based contexts can be created. 502 * 503 * Since this is the first open, ensure that all existing 504 * contexts are invalidated. 505 */ 506 kcpc_invalidate_all(); 507 } else if (BT_TEST(kcpc_cpumap, cpuid)) { 508 kcpc_cpuctx--; 509 rw_exit(&kcpc_cpuctx_lock); 510 return (EAGAIN); 511 } else if (kcpc_hw_cpu_hook(cpuid, kcpc_cpumap) != 0) { 512 kcpc_cpuctx--; 513 rw_exit(&kcpc_cpuctx_lock); 514 return (EACCES); 515 } 516 BT_SET(kcpc_cpumap, cpuid); 517 rw_exit(&kcpc_cpuctx_lock); 518 519 *dev = makedevice(getmajor(*dev), (minor_t)cpuid); 520 521 return (0); 522 } 523 524 /*ARGSUSED1*/ 525 static int 526 kcpc_close(dev_t dev, int flags, int otyp, cred_t *cr) 527 { 528 rw_enter(&kcpc_cpuctx_lock, RW_WRITER); 529 BT_CLEAR(kcpc_cpumap, getminor(dev)); 530 if (--kcpc_cpuctx == 0) { 531 kmem_free(kcpc_cpumap, BT_SIZEOFMAP(max_cpuid + 1)); 532 kcpc_cpumap = NULL; 533 } 534 ASSERT(kcpc_cpuctx >= 0); 535 rw_exit(&kcpc_cpuctx_lock); 536 537 return (0); 538 } 539 540 /* 541 * Sane boundaries on the size of packed lists. In bytes. 542 */ 543 #define CPC_MIN_PACKSIZE 4 544 #define CPC_MAX_PACKSIZE 10000 545 546 /* 547 * Sane boundary on the number of requests a set can contain. 548 */ 549 #define CPC_MAX_NREQS 100 550 551 /* 552 * Sane boundary on the number of attributes a request can contain. 553 */ 554 #define CPC_MAX_ATTRS 50 555 556 /* 557 * Copy in a packed nvlist from the user and create a request set out of it. 558 * If successful, return 0 and store a pointer to the set we've created. Returns 559 * error code on error. 560 */ 561 int 562 kcpc_copyin_set(kcpc_set_t **inset, void *ubuf, size_t len) 563 { 564 kcpc_set_t *set; 565 int i; 566 int j; 567 char *packbuf; 568 569 nvlist_t *nvl; 570 nvpair_t *nvp = NULL; 571 572 nvlist_t *attrs; 573 nvpair_t *nvp_attr; 574 kcpc_attr_t *attrp; 575 576 nvlist_t **reqlist; 577 uint_t nreqs; 578 uint64_t uint64; 579 uint32_t uint32; 580 uint32_t setflags = (uint32_t)-1; 581 char *string; 582 char *name; 583 584 if (len < CPC_MIN_PACKSIZE || len > CPC_MAX_PACKSIZE) 585 return (EINVAL); 586 587 packbuf = kmem_alloc(len, KM_SLEEP); 588 589 if (copyin(ubuf, packbuf, len) == -1) { 590 kmem_free(packbuf, len); 591 return (EFAULT); 592 } 593 594 if (nvlist_unpack(packbuf, len, &nvl, KM_SLEEP) != 0) { 595 kmem_free(packbuf, len); 596 return (EINVAL); 597 } 598 599 /* 600 * The nvlist has been unpacked so there is no need for the packed 601 * representation from this point on. 602 */ 603 kmem_free(packbuf, len); 604 605 i = 0; 606 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 607 switch (nvpair_type(nvp)) { 608 case DATA_TYPE_UINT32: 609 if (strcmp(nvpair_name(nvp), "flags") != 0 || 610 nvpair_value_uint32(nvp, &setflags) != 0) { 611 nvlist_free(nvl); 612 return (EINVAL); 613 } 614 break; 615 case DATA_TYPE_NVLIST_ARRAY: 616 if (strcmp(nvpair_name(nvp), "reqs") != 0 || 617 nvpair_value_nvlist_array(nvp, &reqlist, 618 &nreqs) != 0) { 619 nvlist_free(nvl); 620 return (EINVAL); 621 } 622 break; 623 default: 624 nvlist_free(nvl); 625 return (EINVAL); 626 } 627 i++; 628 } 629 630 /* 631 * There should be two members in the top-level nvlist: 632 * an array of nvlists consisting of the requests, and flags. 633 * Anything else is an invalid set. 634 */ 635 if (i != 2) { 636 nvlist_free(nvl); 637 return (EINVAL); 638 } 639 640 if (nreqs > CPC_MAX_NREQS) { 641 nvlist_free(nvl); 642 return (EINVAL); 643 } 644 645 /* 646 * The requests are now stored in the nvlist array at reqlist. 647 * Note that the use of kmem_zalloc() to alloc the kcpc_set_t means 648 * we don't need to call the init routines for ks_lock and ks_condv. 649 */ 650 set = kmem_zalloc(sizeof (kcpc_set_t), KM_SLEEP); 651 set->ks_req = (kcpc_request_t *)kmem_zalloc(sizeof (kcpc_request_t) * 652 nreqs, KM_SLEEP); 653 set->ks_nreqs = nreqs; 654 /* 655 * If the nvlist didn't contain a flags member, setflags was initialized 656 * with an illegal value and this set will fail sanity checks later on. 657 */ 658 set->ks_flags = setflags; 659 /* 660 * Initialize bind/unbind set synchronization. 661 */ 662 set->ks_state &= ~KCPC_SET_BOUND; 663 664 /* 665 * Build the set up one request at a time, always keeping it self- 666 * consistent so we can give it to kcpc_free_set() if we need to back 667 * out and return and error. 668 */ 669 for (i = 0; i < nreqs; i++) { 670 nvp = NULL; 671 set->ks_req[i].kr_picnum = -1; 672 while ((nvp = nvlist_next_nvpair(reqlist[i], nvp)) != NULL) { 673 name = nvpair_name(nvp); 674 switch (nvpair_type(nvp)) { 675 case DATA_TYPE_UINT32: 676 if (nvpair_value_uint32(nvp, &uint32) == EINVAL) 677 goto inval; 678 if (strcmp(name, "cr_flags") == 0) 679 set->ks_req[i].kr_flags = uint32; 680 if (strcmp(name, "cr_index") == 0) 681 set->ks_req[i].kr_index = uint32; 682 break; 683 case DATA_TYPE_UINT64: 684 if (nvpair_value_uint64(nvp, &uint64) == EINVAL) 685 goto inval; 686 if (strcmp(name, "cr_preset") == 0) 687 set->ks_req[i].kr_preset = uint64; 688 break; 689 case DATA_TYPE_STRING: 690 if (nvpair_value_string(nvp, &string) == EINVAL) 691 goto inval; 692 if (strcmp(name, "cr_event") == 0) 693 (void) strncpy(set->ks_req[i].kr_event, 694 string, CPC_MAX_EVENT_LEN); 695 break; 696 case DATA_TYPE_NVLIST: 697 if (strcmp(name, "cr_attr") != 0) 698 goto inval; 699 if (nvpair_value_nvlist(nvp, &attrs) == EINVAL) 700 goto inval; 701 nvp_attr = NULL; 702 /* 703 * If the picnum has been specified as an 704 * attribute, consume that attribute here and 705 * remove it from the list of attributes. 706 */ 707 if (nvlist_lookup_uint64(attrs, "picnum", 708 &uint64) == 0) { 709 if (nvlist_remove(attrs, "picnum", 710 DATA_TYPE_UINT64) != 0) 711 panic("nvlist %p faulty", 712 (void *)attrs); 713 set->ks_req[i].kr_picnum = uint64; 714 } 715 716 if ((set->ks_req[i].kr_nattrs = 717 kcpc_nvlist_npairs(attrs)) == 0) 718 break; 719 720 if (set->ks_req[i].kr_nattrs > CPC_MAX_ATTRS) 721 goto inval; 722 723 set->ks_req[i].kr_attr = 724 kmem_alloc(set->ks_req[i].kr_nattrs * 725 sizeof (kcpc_attr_t), KM_SLEEP); 726 j = 0; 727 728 while ((nvp_attr = nvlist_next_nvpair(attrs, 729 nvp_attr)) != NULL) { 730 attrp = &set->ks_req[i].kr_attr[j]; 731 732 if (nvpair_type(nvp_attr) != 733 DATA_TYPE_UINT64) 734 goto inval; 735 736 (void) strncpy(attrp->ka_name, 737 nvpair_name(nvp_attr), 738 CPC_MAX_ATTR_LEN); 739 740 if (nvpair_value_uint64(nvp_attr, 741 &(attrp->ka_val)) == EINVAL) 742 goto inval; 743 j++; 744 } 745 ASSERT(j == set->ks_req[i].kr_nattrs); 746 default: 747 break; 748 } 749 } 750 } 751 752 nvlist_free(nvl); 753 *inset = set; 754 return (0); 755 756 inval: 757 nvlist_free(nvl); 758 kcpc_free_set(set); 759 return (EINVAL); 760 } 761 762 /* 763 * Count the number of nvpairs in the supplied nvlist. 764 */ 765 static uint32_t 766 kcpc_nvlist_npairs(nvlist_t *list) 767 { 768 nvpair_t *nvp = NULL; 769 uint32_t n = 0; 770 771 while ((nvp = nvlist_next_nvpair(list, nvp)) != NULL) 772 n++; 773 774 return (n); 775 } 776 777 /* 778 * Performs sanity checks on the given set. 779 * Returns 0 if the set checks out OK. 780 * Returns a detailed error subcode, or -1 if there is no applicable subcode. 781 */ 782 static int 783 kcpc_verify_set(kcpc_set_t *set) 784 { 785 kcpc_request_t *rp; 786 int i; 787 uint64_t bitmap = 0; 788 int n; 789 790 if (set->ks_nreqs > cpc_ncounters) 791 return (-1); 792 793 if (CPC_SET_VALID_FLAGS(set->ks_flags) == 0) 794 return (-1); 795 796 for (i = 0; i < set->ks_nreqs; i++) { 797 rp = &set->ks_req[i]; 798 799 /* 800 * The following comparison must cast cpc_ncounters to an int, 801 * because kr_picnum will be -1 if the request didn't explicitly 802 * choose a PIC. 803 */ 804 if (rp->kr_picnum >= (int)cpc_ncounters) 805 return (CPC_INVALID_PICNUM); 806 807 /* 808 * Of the pics whose physical picnum has been specified, make 809 * sure each PIC appears only once in set. 810 */ 811 if ((n = set->ks_req[i].kr_picnum) != -1) { 812 if ((bitmap & (1 << n)) != 0) 813 return (-1); 814 bitmap |= (1 << n); 815 } 816 817 /* 818 * Make sure the requested index falls within the range of all 819 * requests. 820 */ 821 if (rp->kr_index < 0 || rp->kr_index >= set->ks_nreqs) 822 return (-1); 823 824 /* 825 * Make sure there are no unknown flags. 826 */ 827 if (KCPC_REQ_VALID_FLAGS(rp->kr_flags) == 0) 828 return (CPC_REQ_INVALID_FLAGS); 829 } 830 831 return (0); 832 } 833 834 static struct cb_ops cb_ops = { 835 kcpc_open, 836 kcpc_close, 837 nodev, /* strategy */ 838 nodev, /* print */ 839 nodev, /* dump */ 840 nodev, /* read */ 841 nodev, /* write */ 842 kcpc_ioctl, 843 nodev, /* devmap */ 844 nodev, /* mmap */ 845 nodev, /* segmap */ 846 nochpoll, /* poll */ 847 ddi_prop_op, 848 NULL, 849 D_NEW | D_MP 850 }; 851 852 /*ARGSUSED*/ 853 static int 854 kcpc_probe(dev_info_t *devi) 855 { 856 return (DDI_PROBE_SUCCESS); 857 } 858 859 static dev_info_t *kcpc_devi; 860 861 static int 862 kcpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 863 { 864 if (cmd != DDI_ATTACH) 865 return (DDI_FAILURE); 866 kcpc_devi = devi; 867 return (ddi_create_minor_node(devi, "shared", S_IFCHR, 868 KCPC_MINOR_SHARED, DDI_PSEUDO, 0)); 869 } 870 871 /*ARGSUSED*/ 872 static int 873 kcpc_getinfo(dev_info_t *devi, ddi_info_cmd_t cmd, void *arg, void **result) 874 { 875 switch (cmd) { 876 case DDI_INFO_DEVT2DEVINFO: 877 switch (getminor((dev_t)arg)) { 878 case KCPC_MINOR_SHARED: 879 *result = kcpc_devi; 880 return (DDI_SUCCESS); 881 default: 882 break; 883 } 884 break; 885 case DDI_INFO_DEVT2INSTANCE: 886 *result = 0; 887 return (DDI_SUCCESS); 888 default: 889 break; 890 } 891 892 return (DDI_FAILURE); 893 } 894 895 static struct dev_ops dev_ops = { 896 DEVO_REV, 897 0, 898 kcpc_getinfo, 899 nulldev, /* identify */ 900 kcpc_probe, 901 kcpc_attach, 902 nodev, /* detach */ 903 nodev, /* reset */ 904 &cb_ops, 905 (struct bus_ops *)0, 906 NULL, 907 ddi_quiesce_not_needed, /* quiesce */ 908 }; 909 910 static struct modldrv modldrv = { 911 &mod_driverops, 912 "cpc sampling driver", 913 &dev_ops 914 }; 915 916 static struct sysent cpc_sysent = { 917 5, 918 SE_NOUNLOAD | SE_ARGC | SE_32RVAL1, 919 cpc 920 }; 921 922 static struct modlsys modlsys = { 923 &mod_syscallops, 924 "cpc sampling system call", 925 &cpc_sysent 926 }; 927 928 #ifdef _SYSCALL32_IMPL 929 static struct modlsys modlsys32 = { 930 &mod_syscallops32, 931 "32-bit cpc sampling system call", 932 &cpc_sysent 933 }; 934 #endif 935 936 static struct modlinkage modl = { 937 MODREV_1, { 938 &modldrv, 939 &modlsys, 940 #ifdef _SYSCALL32_IMPL 941 &modlsys32, 942 #endif 943 NULL 944 } 945 }; 946 947 int 948 _init(void) 949 { 950 if (kcpc_init() != 0) 951 return (ENOTSUP); 952 953 return (mod_install(&modl)); 954 } 955 956 int 957 _fini(void) 958 { 959 return (mod_remove(&modl)); 960 } 961 962 int 963 _info(struct modinfo *mi) 964 { 965 return (mod_info(&modl, mi)); 966 }