17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55d3a5ad8Srab * Common Development and Distribution License (the "License"). 65d3a5ad8Srab * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22e850fb01SKuriakose Kuruvilla * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <libcpc.h> 277c478bd9Sstevel@tonic-gate #include <stdio.h> 287c478bd9Sstevel@tonic-gate #include <stdlib.h> 297c478bd9Sstevel@tonic-gate #include <errno.h> 307c478bd9Sstevel@tonic-gate #include <strings.h> 317c478bd9Sstevel@tonic-gate #include <unistd.h> 327c478bd9Sstevel@tonic-gate #include <stropts.h> 337c478bd9Sstevel@tonic-gate #include <libintl.h> 347c478bd9Sstevel@tonic-gate #include <signal.h> 357c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 367c478bd9Sstevel@tonic-gate #include <sys/types.h> 377c478bd9Sstevel@tonic-gate #include <sys/processor.h> 387c478bd9Sstevel@tonic-gate #include <sys/procset.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include "libcpc_impl.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #define MASK32 0xFFFFFFFF 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * The library uses the cpc_lock field of the cpc_t struct to protect access to 467c478bd9Sstevel@tonic-gate * the linked lists inside the cpc_t, and only the linked lists. It is NOT used 477c478bd9Sstevel@tonic-gate * to protect against a user shooting his/herself in the foot (such as, for 487c478bd9Sstevel@tonic-gate * instance, destroying the same set at the same time from different threads.). 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * SIGEMT needs to be blocked while holding the lock, to prevent deadlock among 517c478bd9Sstevel@tonic-gate * an app holding the lock and a signal handler attempting to sample or bind. 527c478bd9Sstevel@tonic-gate */ 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate static char *cpc_get_list(int which, int arg); 557c478bd9Sstevel@tonic-gate static void cpc_err(cpc_t *cpc, const char *fn, int subcode, ...); 567c478bd9Sstevel@tonic-gate static int cpc_set_valid(cpc_t *cpc, cpc_set_t *set); 577c478bd9Sstevel@tonic-gate static int cpc_lock(cpc_t *cpc); 587c478bd9Sstevel@tonic-gate static void cpc_unlock(cpc_t *cpc, int blocked); 597c478bd9Sstevel@tonic-gate static int cpc_valid_event(cpc_t *cpc, uint_t pic, const char *ev); 607c478bd9Sstevel@tonic-gate static int cpc_valid_attr(cpc_t *cpc, char *attr); 617c478bd9Sstevel@tonic-gate static void cpc_invalidate_pctx(cpc_t *cpc, pctx_t *pctx); 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate cpc_t * 647c478bd9Sstevel@tonic-gate cpc_open(int ver) 657c478bd9Sstevel@tonic-gate { 667c478bd9Sstevel@tonic-gate cpc_t *cpc; 677c478bd9Sstevel@tonic-gate void (*sigsaved)(); 687c478bd9Sstevel@tonic-gate int error = 0; 697c478bd9Sstevel@tonic-gate int i; 707c478bd9Sstevel@tonic-gate int j; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate if (ver != CPC_VER_CURRENT) { 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * v1 clients must stick to the v1 interface: cpc_version() 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate errno = EINVAL; 777c478bd9Sstevel@tonic-gate return (NULL); 787c478bd9Sstevel@tonic-gate } 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * Call the syscall with invalid parameters. If we get ENOSYS this CPU 827c478bd9Sstevel@tonic-gate * has no CPC support. We need to block SIGSYS because the syscall code 837c478bd9Sstevel@tonic-gate * will send the signal if the system call fails to load. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate sigsaved = signal(SIGSYS, SIG_IGN); 867c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, -1, -1, -1, -1, -1) != -1) { 877c478bd9Sstevel@tonic-gate (void) signal(SIGSYS, sigsaved); 887c478bd9Sstevel@tonic-gate errno = EINVAL; 897c478bd9Sstevel@tonic-gate return (NULL); 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate error = errno; 927c478bd9Sstevel@tonic-gate (void) signal(SIGSYS, sigsaved); 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate if (error != EINVAL) { 957c478bd9Sstevel@tonic-gate errno = error; 967c478bd9Sstevel@tonic-gate return (NULL); 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate if ((cpc = malloc(sizeof (cpc_t))) == NULL) { 1007c478bd9Sstevel@tonic-gate errno = ENOMEM; 1017c478bd9Sstevel@tonic-gate return (NULL); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate cpc->cpc_npic = syscall(SYS_cpc, CPC_NPIC, -1, 0, 0, 0); 1057c478bd9Sstevel@tonic-gate cpc->cpc_caps = syscall(SYS_cpc, CPC_CAPS, -1, 0, 0, 0); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, CPC_IMPL_NAME, -1, &cpc->cpc_cciname, 0, 0) != 0) 1087c478bd9Sstevel@tonic-gate return (NULL); 1097c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, CPC_CPUREF, -1, &cpc->cpc_cpuref, 0, 0) != 0) 1107c478bd9Sstevel@tonic-gate return (NULL); 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate if ((cpc->cpc_attrlist = cpc_get_list(CPC_LIST_ATTRS, 0)) == NULL) { 1147c478bd9Sstevel@tonic-gate free(cpc); 1157c478bd9Sstevel@tonic-gate return (NULL); 1167c478bd9Sstevel@tonic-gate } 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate if ((cpc->cpc_evlist = malloc(cpc->cpc_npic * sizeof (char *))) == 1197c478bd9Sstevel@tonic-gate NULL) { 1207c478bd9Sstevel@tonic-gate free(cpc->cpc_attrlist); 1217c478bd9Sstevel@tonic-gate free(cpc); 1227c478bd9Sstevel@tonic-gate return (NULL); 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate for (i = 0; i < cpc->cpc_npic; i++) { 1267c478bd9Sstevel@tonic-gate if ((cpc->cpc_evlist[i] = cpc_get_list(CPC_LIST_EVENTS, i)) == 1277c478bd9Sstevel@tonic-gate NULL) 1287c478bd9Sstevel@tonic-gate break; 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate if (i != cpc->cpc_npic) { 1317c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) 1327c478bd9Sstevel@tonic-gate free(cpc->cpc_evlist[j]); 1337c478bd9Sstevel@tonic-gate free(cpc->cpc_evlist); 1347c478bd9Sstevel@tonic-gate free(cpc->cpc_attrlist); 1357c478bd9Sstevel@tonic-gate free(cpc); 1367c478bd9Sstevel@tonic-gate return (NULL); 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate cpc->cpc_sets = NULL; 1407c478bd9Sstevel@tonic-gate cpc->cpc_bufs = NULL; 1417c478bd9Sstevel@tonic-gate cpc->cpc_errfn = NULL; 1427c478bd9Sstevel@tonic-gate (void) mutex_init(&cpc->cpc_lock, USYNC_THREAD, NULL); 1437c478bd9Sstevel@tonic-gate __pctx_cpc_register_callback(cpc_invalidate_pctx); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate return (cpc); 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Ensure state is cleaned up: 1507c478bd9Sstevel@tonic-gate * 1517c478bd9Sstevel@tonic-gate * - Hardware is unbound 1527c478bd9Sstevel@tonic-gate * - Sets are all destroyed 1537c478bd9Sstevel@tonic-gate * - Bufs are all freed 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate int 1567c478bd9Sstevel@tonic-gate cpc_close(cpc_t *cpc) 1577c478bd9Sstevel@tonic-gate { 1587c478bd9Sstevel@tonic-gate while (cpc->cpc_sets != NULL) { 1597c478bd9Sstevel@tonic-gate if (cpc->cpc_sets->cs_state != CS_UNBOUND) 1607c478bd9Sstevel@tonic-gate (void) cpc_unbind(cpc, cpc->cpc_sets); 1617c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, cpc->cpc_sets); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate while (cpc->cpc_bufs != NULL) 1657c478bd9Sstevel@tonic-gate (void) cpc_buf_destroy(cpc, cpc->cpc_bufs); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate free(cpc); 1687c478bd9Sstevel@tonic-gate return (0); 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 171*b885580bSAlexander Kolbasov /* 172*b885580bSAlexander Kolbasov * Terminate everything that runs in pctx_run 173*b885580bSAlexander Kolbasov */ 174*b885580bSAlexander Kolbasov void 175*b885580bSAlexander Kolbasov cpc_terminate(cpc_t *cpc) 176*b885580bSAlexander Kolbasov { 177*b885580bSAlexander Kolbasov cpc_set_t *csp; 178*b885580bSAlexander Kolbasov int sigblocked; 179*b885580bSAlexander Kolbasov 180*b885580bSAlexander Kolbasov sigblocked = cpc_lock(cpc); 181*b885580bSAlexander Kolbasov for (csp = cpc->cpc_sets; csp != NULL; csp = csp->cs_next) { 182*b885580bSAlexander Kolbasov if (csp->cs_pctx != NULL) 183*b885580bSAlexander Kolbasov pctx_terminate(csp->cs_pctx); 184*b885580bSAlexander Kolbasov } 185*b885580bSAlexander Kolbasov cpc_unlock(cpc, sigblocked); 186*b885580bSAlexander Kolbasov } 187*b885580bSAlexander Kolbasov 1887c478bd9Sstevel@tonic-gate cpc_set_t * 1897c478bd9Sstevel@tonic-gate cpc_set_create(cpc_t *cpc) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate cpc_set_t *set; 1927c478bd9Sstevel@tonic-gate int sigblocked; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if ((set = malloc(sizeof (*set))) == NULL) { 1957c478bd9Sstevel@tonic-gate errno = ENOMEM; 1967c478bd9Sstevel@tonic-gate return (NULL); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate set->cs_request = NULL; 2007c478bd9Sstevel@tonic-gate set->cs_nreqs = 0; 2017c478bd9Sstevel@tonic-gate set->cs_state = CS_UNBOUND; 2027c478bd9Sstevel@tonic-gate set->cs_fd = -1; 2037c478bd9Sstevel@tonic-gate set->cs_pctx = NULL; 2047c478bd9Sstevel@tonic-gate set->cs_id = -1; 2057c478bd9Sstevel@tonic-gate set->cs_thr = NULL; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 2087c478bd9Sstevel@tonic-gate set->cs_next = cpc->cpc_sets; 2097c478bd9Sstevel@tonic-gate cpc->cpc_sets = set; 2107c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate return (set); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate int 2167c478bd9Sstevel@tonic-gate cpc_set_destroy(cpc_t *cpc, cpc_set_t *set) 2177c478bd9Sstevel@tonic-gate { 2187c478bd9Sstevel@tonic-gate cpc_set_t *csp, *prev; 2197c478bd9Sstevel@tonic-gate cpc_request_t *req, *next; 2207c478bd9Sstevel@tonic-gate int sigblocked; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* 2237c478bd9Sstevel@tonic-gate * Remove this set from the cpc handle's list of sets. 2247c478bd9Sstevel@tonic-gate */ 2257c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 2267c478bd9Sstevel@tonic-gate for (csp = prev = cpc->cpc_sets; csp != NULL; csp = csp->cs_next) { 2277c478bd9Sstevel@tonic-gate if (csp == set) 2287c478bd9Sstevel@tonic-gate break; 2297c478bd9Sstevel@tonic-gate prev = csp; 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate if (csp == NULL) { 2327c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 2337c478bd9Sstevel@tonic-gate errno = EINVAL; 2347c478bd9Sstevel@tonic-gate return (-1); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate if (csp == cpc->cpc_sets) 2377c478bd9Sstevel@tonic-gate cpc->cpc_sets = csp->cs_next; 2387c478bd9Sstevel@tonic-gate prev->cs_next = csp->cs_next; 2397c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate if (csp->cs_state != CS_UNBOUND) 2427c478bd9Sstevel@tonic-gate (void) cpc_unbind(cpc, csp); 2437c478bd9Sstevel@tonic-gate 244*b885580bSAlexander Kolbasov /* 245*b885580bSAlexander Kolbasov * Detach from the process 246*b885580bSAlexander Kolbasov */ 247*b885580bSAlexander Kolbasov if (csp->cs_pctx != NULL) { 248*b885580bSAlexander Kolbasov pctx_release(csp->cs_pctx); 249*b885580bSAlexander Kolbasov csp->cs_pctx = NULL; 250*b885580bSAlexander Kolbasov } 251*b885580bSAlexander Kolbasov 2527c478bd9Sstevel@tonic-gate for (req = csp->cs_request; req != NULL; req = next) { 2537c478bd9Sstevel@tonic-gate next = req->cr_next; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate if (req->cr_nattrs != 0) 2567c478bd9Sstevel@tonic-gate free(req->cr_attr); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate free(req); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate free(set); 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate return (0); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2687c478bd9Sstevel@tonic-gate int 2697c478bd9Sstevel@tonic-gate cpc_set_add_request(cpc_t *cpc, cpc_set_t *set, const char *event, 2707c478bd9Sstevel@tonic-gate uint64_t preset, uint_t flags, uint_t nattrs, const cpc_attr_t *attrs) 2717c478bd9Sstevel@tonic-gate { 2727c478bd9Sstevel@tonic-gate cpc_request_t *req; 2737c478bd9Sstevel@tonic-gate const char *fn = "cpc_set_add_request"; 2747c478bd9Sstevel@tonic-gate int i; 2757c478bd9Sstevel@tonic-gate int npics = cpc_npic(cpc); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if (cpc_set_valid(cpc, set) != 0 || set->cs_state != CS_UNBOUND) { 2787c478bd9Sstevel@tonic-gate errno = EINVAL; 2797c478bd9Sstevel@tonic-gate return (-1); 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate for (i = 0; i < npics; i++) 2837c478bd9Sstevel@tonic-gate if (cpc_valid_event(cpc, i, event)) 2847c478bd9Sstevel@tonic-gate break; 2857c478bd9Sstevel@tonic-gate if (i == npics) { 2867c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, CPC_INVALID_EVENT); 2877c478bd9Sstevel@tonic-gate errno = EINVAL; 2887c478bd9Sstevel@tonic-gate return (-1); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate if ((req = malloc(sizeof (*req))) == NULL) { 2927c478bd9Sstevel@tonic-gate errno = ENOMEM; 2937c478bd9Sstevel@tonic-gate return (-1); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate (void) strncpy(req->cr_event, event, CPC_MAX_EVENT_LEN); 2977c478bd9Sstevel@tonic-gate req->cr_preset = preset; 2987c478bd9Sstevel@tonic-gate req->cr_flags = flags; 2997c478bd9Sstevel@tonic-gate req->cr_nattrs = nattrs; 3007c478bd9Sstevel@tonic-gate req->cr_index = set->cs_nreqs; 3017c478bd9Sstevel@tonic-gate req->cr_attr = NULL; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate if (nattrs != 0) { 3047c478bd9Sstevel@tonic-gate for (i = 0; i < nattrs; i++) { 3057c478bd9Sstevel@tonic-gate /* 3067c478bd9Sstevel@tonic-gate * Verify that each attribute name is legal and valid. 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate if (attrs[i].ca_name[0] == '\0' || 3097c478bd9Sstevel@tonic-gate cpc_valid_attr(cpc, attrs[i].ca_name) == 0) { 3107c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, CPC_INVALID_ATTRIBUTE); 3117c478bd9Sstevel@tonic-gate goto inval; 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * If the user requested a specific picnum, ensure that 3167c478bd9Sstevel@tonic-gate * the pic can count the requested event. 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate if (strncmp("picnum", attrs[i].ca_name, 8) == 0) { 3197c478bd9Sstevel@tonic-gate if (attrs[i].ca_val >= npics) { 3207c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, CPC_INVALID_PICNUM); 3217c478bd9Sstevel@tonic-gate goto inval; 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate if (cpc_valid_event(cpc, attrs[i].ca_val, 3257c478bd9Sstevel@tonic-gate req->cr_event) == 0) { 3267c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, CPC_PIC_NOT_CAPABLE); 3277c478bd9Sstevel@tonic-gate goto inval; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate if ((req->cr_attr = malloc(nattrs * sizeof (kcpc_attr_t))) 3337c478bd9Sstevel@tonic-gate == NULL) { 3347c478bd9Sstevel@tonic-gate free(req); 3357c478bd9Sstevel@tonic-gate return (-1); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate for (i = 0; i < nattrs; i++) { 3397c478bd9Sstevel@tonic-gate req->cr_attr[i].ka_val = attrs[i].ca_val; 3407c478bd9Sstevel@tonic-gate (void) strncpy(req->cr_attr[i].ka_name, 3417c478bd9Sstevel@tonic-gate attrs[i].ca_name, CPC_MAX_ATTR_LEN); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate } else 3447c478bd9Sstevel@tonic-gate req->cr_attr = NULL; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate req->cr_next = set->cs_request; 3477c478bd9Sstevel@tonic-gate set->cs_request = req; 3487c478bd9Sstevel@tonic-gate set->cs_nreqs++; 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate return (req->cr_index); 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate inval: 3537c478bd9Sstevel@tonic-gate free(req); 3547c478bd9Sstevel@tonic-gate errno = EINVAL; 3557c478bd9Sstevel@tonic-gate return (-1); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate cpc_buf_t * 3597c478bd9Sstevel@tonic-gate cpc_buf_create(cpc_t *cpc, cpc_set_t *set) 3607c478bd9Sstevel@tonic-gate { 3617c478bd9Sstevel@tonic-gate cpc_buf_t *buf; 3627c478bd9Sstevel@tonic-gate int sigblocked; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate if (cpc_set_valid(cpc, set) != 0) { 3657c478bd9Sstevel@tonic-gate errno = EINVAL; 3667c478bd9Sstevel@tonic-gate return (NULL); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate if ((buf = malloc(sizeof (*buf))) == NULL) 3707c478bd9Sstevel@tonic-gate return (NULL); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate buf->cb_size = set->cs_nreqs * sizeof (uint64_t); 3737c478bd9Sstevel@tonic-gate if ((buf->cb_data = malloc(buf->cb_size)) == NULL) { 3747c478bd9Sstevel@tonic-gate free(buf); 3757c478bd9Sstevel@tonic-gate return (NULL); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate bzero(buf->cb_data, buf->cb_size); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate buf->cb_hrtime = 0; 3817c478bd9Sstevel@tonic-gate buf->cb_tick = 0; 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 3847c478bd9Sstevel@tonic-gate buf->cb_next = cpc->cpc_bufs; 3857c478bd9Sstevel@tonic-gate cpc->cpc_bufs = buf; 3867c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate return (buf); 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate int 3927c478bd9Sstevel@tonic-gate cpc_buf_destroy(cpc_t *cpc, cpc_buf_t *buf) 3937c478bd9Sstevel@tonic-gate { 3947c478bd9Sstevel@tonic-gate cpc_buf_t *cbp, *prev; 3957c478bd9Sstevel@tonic-gate int sigblocked; 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * Remove this buf from the cpc handle's list of bufs. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 4017c478bd9Sstevel@tonic-gate for (cbp = prev = cpc->cpc_bufs; cbp != NULL; cbp = cbp->cb_next) { 4027c478bd9Sstevel@tonic-gate if (cbp == buf) 4037c478bd9Sstevel@tonic-gate break; 4047c478bd9Sstevel@tonic-gate prev = cbp; 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate if (cbp == NULL) { 4077c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 4087c478bd9Sstevel@tonic-gate errno = EINVAL; 4097c478bd9Sstevel@tonic-gate return (-1); 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate if (cbp == cpc->cpc_bufs) 4127c478bd9Sstevel@tonic-gate cpc->cpc_bufs = cbp->cb_next; 4137c478bd9Sstevel@tonic-gate prev->cb_next = cbp->cb_next; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 4167c478bd9Sstevel@tonic-gate free(cbp->cb_data); 4177c478bd9Sstevel@tonic-gate free(cbp); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate return (0); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4237c478bd9Sstevel@tonic-gate int 4247c478bd9Sstevel@tonic-gate cpc_bind_curlwp(cpc_t *cpc, cpc_set_t *set, uint_t flags) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate char *packed_set; 4277c478bd9Sstevel@tonic-gate size_t packsize; 4287c478bd9Sstevel@tonic-gate int ret; 4297c478bd9Sstevel@tonic-gate int subcode = -1; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* 4327c478bd9Sstevel@tonic-gate * We don't bother checking cpc_set_valid() here, because this is in the 4337c478bd9Sstevel@tonic-gate * fast path of an app doing SIGEMT-based profiling as they restart the 4347c478bd9Sstevel@tonic-gate * counters from their signal handler. 4357c478bd9Sstevel@tonic-gate */ 4367c478bd9Sstevel@tonic-gate if (CPC_SET_VALID_FLAGS(flags) == 0 || set->cs_nreqs <= 0) { 4377c478bd9Sstevel@tonic-gate errno = EINVAL; 4387c478bd9Sstevel@tonic-gate return (-1); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 4427c478bd9Sstevel@tonic-gate errno = ENOMEM; 4437c478bd9Sstevel@tonic-gate return (-1); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate ret = syscall(SYS_cpc, CPC_BIND, -1, packed_set, packsize, &subcode); 4477c478bd9Sstevel@tonic-gate free(packed_set); 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate if (ret != 0) { 4507c478bd9Sstevel@tonic-gate if (subcode != -1) 4517c478bd9Sstevel@tonic-gate cpc_err(cpc, "cpc_bind_curlwp", subcode); 4527c478bd9Sstevel@tonic-gate return (-1); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate set->cs_thr = thr_self(); 4567c478bd9Sstevel@tonic-gate set->cs_state = CS_BOUND_CURLWP; 4577c478bd9Sstevel@tonic-gate return (ret); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4617c478bd9Sstevel@tonic-gate int 4627c478bd9Sstevel@tonic-gate cpc_bind_pctx(cpc_t *cpc, pctx_t *pctx, id_t id, cpc_set_t *set, uint_t flags) 4637c478bd9Sstevel@tonic-gate { 4647c478bd9Sstevel@tonic-gate char *packed_set; 4657c478bd9Sstevel@tonic-gate size_t packsize; 4667c478bd9Sstevel@tonic-gate int ret; 4677c478bd9Sstevel@tonic-gate int subcode = -1; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /* 4707c478bd9Sstevel@tonic-gate * cpc_bind_pctx() currently has no valid flags. 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate if (flags != 0 || cpc_set_valid(cpc, set) != 0 || set->cs_nreqs <= 0) { 4737c478bd9Sstevel@tonic-gate errno = EINVAL; 4747c478bd9Sstevel@tonic-gate return (-1); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 4787c478bd9Sstevel@tonic-gate errno = ENOMEM; 4797c478bd9Sstevel@tonic-gate return (-1); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate ret = __pctx_cpc(pctx, cpc, CPC_BIND, id, packed_set, (void *)packsize, 4837c478bd9Sstevel@tonic-gate (void *)&subcode, -1); 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate free(packed_set); 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate if (ret == 0) { 4887c478bd9Sstevel@tonic-gate set->cs_pctx = pctx; 4897c478bd9Sstevel@tonic-gate set->cs_id = id; 4907c478bd9Sstevel@tonic-gate set->cs_state = CS_BOUND_PCTX; 4917c478bd9Sstevel@tonic-gate } else if (subcode != -1) 4927c478bd9Sstevel@tonic-gate cpc_err(cpc, "cpc_bind_pctx", subcode); 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate return (ret); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4987c478bd9Sstevel@tonic-gate int 4997c478bd9Sstevel@tonic-gate cpc_bind_cpu(cpc_t *cpc, processorid_t id, cpc_set_t *set, uint_t flags) 5007c478bd9Sstevel@tonic-gate { 5017c478bd9Sstevel@tonic-gate int fd; 5027c478bd9Sstevel@tonic-gate char *packed_set; 5037c478bd9Sstevel@tonic-gate size_t packsize; 5047c478bd9Sstevel@tonic-gate __cpc_args_t cpc_args; 5057c478bd9Sstevel@tonic-gate int error; 5067c478bd9Sstevel@tonic-gate const char *fn = "cpc_bind_cpu"; 5077c478bd9Sstevel@tonic-gate int subcode = -1; 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * cpc_bind_cpu() currently has no valid flags. 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate if (flags != 0 || cpc_set_valid(cpc, set) != 0 || set->cs_nreqs <= 0) { 5137c478bd9Sstevel@tonic-gate errno = EINVAL; 5147c478bd9Sstevel@tonic-gate return (-1); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate if (processor_bind(P_LWPID, P_MYID, id, &set->cs_obind) == -1) { 5187c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, CPC_PBIND_FAILED); 5197c478bd9Sstevel@tonic-gate return (-1); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate if ((fd = open(CPUDRV_SHARED, O_RDWR)) < 0) { 5237c478bd9Sstevel@tonic-gate error = errno; 5247c478bd9Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5257c478bd9Sstevel@tonic-gate errno = error; 5267c478bd9Sstevel@tonic-gate return (-1); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* 5307c478bd9Sstevel@tonic-gate * To avoid leaking file descriptors, if we find an existing fd here we 5317c478bd9Sstevel@tonic-gate * just close it. This is only a problem if a user attempts to bind the 5327c478bd9Sstevel@tonic-gate * same set to different CPUs without first unbinding it. 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate if (set->cs_fd != -1) 5357c478bd9Sstevel@tonic-gate (void) close(set->cs_fd); 5367c478bd9Sstevel@tonic-gate set->cs_fd = fd; 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 5397c478bd9Sstevel@tonic-gate (void) close(fd); 5407c478bd9Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5417c478bd9Sstevel@tonic-gate errno = ENOMEM; 5427c478bd9Sstevel@tonic-gate return (-1); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate cpc_args.udata1 = packed_set; 5467c478bd9Sstevel@tonic-gate cpc_args.udata2 = (void *)packsize; 5477c478bd9Sstevel@tonic-gate cpc_args.udata3 = (void *)&subcode; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate if (ioctl(fd, CPCIO_BIND, &cpc_args) != 0) { 5507c478bd9Sstevel@tonic-gate error = errno; 5517c478bd9Sstevel@tonic-gate free(packed_set); 5527c478bd9Sstevel@tonic-gate (void) close(fd); 5537c478bd9Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5547c478bd9Sstevel@tonic-gate if (subcode != -1) 5557c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, subcode); 5567c478bd9Sstevel@tonic-gate errno = error; 5577c478bd9Sstevel@tonic-gate return (-1); 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate free(packed_set); 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate set->cs_thr = thr_self(); 5637c478bd9Sstevel@tonic-gate set->cs_state = CS_BOUND_CPU; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate return (0); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5697c478bd9Sstevel@tonic-gate int 5707c478bd9Sstevel@tonic-gate cpc_request_preset(cpc_t *cpc, int index, uint64_t preset) 5717c478bd9Sstevel@tonic-gate { 5727c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_PRESET, -1, index, 5737c478bd9Sstevel@tonic-gate (uint32_t)(preset >> 32), (uint32_t)(preset & MASK32))); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5777c478bd9Sstevel@tonic-gate int 5787c478bd9Sstevel@tonic-gate cpc_set_restart(cpc_t *cpc, cpc_set_t *set) 5797c478bd9Sstevel@tonic-gate { 5807c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_RESTART, -1, 0, 0, 0)); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5847c478bd9Sstevel@tonic-gate int 5857c478bd9Sstevel@tonic-gate cpc_unbind(cpc_t *cpc, cpc_set_t *set) 5867c478bd9Sstevel@tonic-gate { 5877c478bd9Sstevel@tonic-gate int ret = 0; 5887c478bd9Sstevel@tonic-gate int error; 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate if (cpc_set_valid(cpc, set) != 0) { 5917c478bd9Sstevel@tonic-gate errno = EINVAL; 5927c478bd9Sstevel@tonic-gate return (-1); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate switch (set->cs_state) { 5967c478bd9Sstevel@tonic-gate case CS_UNBOUND: 5977c478bd9Sstevel@tonic-gate errno = EINVAL; 5987c478bd9Sstevel@tonic-gate return (-1); 5997c478bd9Sstevel@tonic-gate case CS_BOUND_CURLWP: 6007c478bd9Sstevel@tonic-gate ret = syscall(SYS_cpc, CPC_RELE, -1, 0, 0, 0); 6017c478bd9Sstevel@tonic-gate error = errno; 6027c478bd9Sstevel@tonic-gate break; 6037c478bd9Sstevel@tonic-gate case CS_BOUND_CPU: 6047c478bd9Sstevel@tonic-gate ret = ioctl(set->cs_fd, CPCIO_RELE, NULL); 6057c478bd9Sstevel@tonic-gate error = errno; 6067c478bd9Sstevel@tonic-gate (void) close(set->cs_fd); 6077c478bd9Sstevel@tonic-gate set->cs_fd = -1; 6087c478bd9Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 6097c478bd9Sstevel@tonic-gate break; 6107c478bd9Sstevel@tonic-gate case CS_BOUND_PCTX: 6117c478bd9Sstevel@tonic-gate if (set->cs_pctx != NULL) { 6127c478bd9Sstevel@tonic-gate ret = __pctx_cpc(set->cs_pctx, cpc, CPC_RELE, 6137c478bd9Sstevel@tonic-gate set->cs_id, 0, 0, 0, 0); 6147c478bd9Sstevel@tonic-gate error = errno; 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate break; 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate set->cs_thr = NULL; 6207c478bd9Sstevel@tonic-gate set->cs_id = -1; 6217c478bd9Sstevel@tonic-gate set->cs_state = CS_UNBOUND; 6227c478bd9Sstevel@tonic-gate if (ret != 0) 6237c478bd9Sstevel@tonic-gate errno = error; 6247c478bd9Sstevel@tonic-gate return (ret); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6287c478bd9Sstevel@tonic-gate int 6297c478bd9Sstevel@tonic-gate cpc_set_sample(cpc_t *cpc, cpc_set_t *set, cpc_buf_t *buf) 6307c478bd9Sstevel@tonic-gate { 6317c478bd9Sstevel@tonic-gate __cpc_args_t args; 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * The following check ensures that only the most recently bound set 6357c478bd9Sstevel@tonic-gate * can be sampled, as binding a set invalidates all other sets in the 6367c478bd9Sstevel@tonic-gate * cpc_t. 6377c478bd9Sstevel@tonic-gate */ 6387c478bd9Sstevel@tonic-gate if (set->cs_state == CS_UNBOUND || 6397c478bd9Sstevel@tonic-gate buf->cb_size != set->cs_nreqs * sizeof (uint64_t)) { 6407c478bd9Sstevel@tonic-gate errno = EINVAL; 6417c478bd9Sstevel@tonic-gate return (-1); 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate switch (set->cs_state) { 6457c478bd9Sstevel@tonic-gate case CS_BOUND_CURLWP: 6467c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_SAMPLE, -1, buf->cb_data, 6477c478bd9Sstevel@tonic-gate &buf->cb_hrtime, &buf->cb_tick)); 6487c478bd9Sstevel@tonic-gate case CS_BOUND_CPU: 6497c478bd9Sstevel@tonic-gate args.udata1 = buf->cb_data; 6507c478bd9Sstevel@tonic-gate args.udata2 = &buf->cb_hrtime; 6517c478bd9Sstevel@tonic-gate args.udata3 = &buf->cb_tick; 6527c478bd9Sstevel@tonic-gate return (ioctl(set->cs_fd, CPCIO_SAMPLE, &args)); 6537c478bd9Sstevel@tonic-gate case CS_BOUND_PCTX: 6547c478bd9Sstevel@tonic-gate return (__pctx_cpc(set->cs_pctx, cpc, CPC_SAMPLE, set->cs_id, 6557c478bd9Sstevel@tonic-gate buf->cb_data, &buf->cb_hrtime, &buf->cb_tick, 6567c478bd9Sstevel@tonic-gate buf->cb_size)); 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate errno = EINVAL; 6607c478bd9Sstevel@tonic-gate return (-1); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6647c478bd9Sstevel@tonic-gate void 6657c478bd9Sstevel@tonic-gate cpc_buf_sub(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *a, cpc_buf_t *b) 6667c478bd9Sstevel@tonic-gate { 6677c478bd9Sstevel@tonic-gate int i; 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate if (a->cb_size != ds->cb_size || b->cb_size != ds->cb_size) 6707c478bd9Sstevel@tonic-gate return; 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate ds->cb_hrtime = (a->cb_hrtime > b->cb_hrtime) ? 6737c478bd9Sstevel@tonic-gate a->cb_hrtime : b->cb_hrtime; 6747c478bd9Sstevel@tonic-gate ds->cb_tick = a->cb_tick - b->cb_tick; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate for (i = 0; i < ds->cb_size / sizeof (uint64_t); i++) 6777c478bd9Sstevel@tonic-gate ds->cb_data[i] = a->cb_data[i] - b->cb_data[i]; 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6817c478bd9Sstevel@tonic-gate void 6827c478bd9Sstevel@tonic-gate cpc_buf_add(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *a, cpc_buf_t *b) 6837c478bd9Sstevel@tonic-gate { 6847c478bd9Sstevel@tonic-gate int i; 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate if (a->cb_size != ds->cb_size || b->cb_size != ds->cb_size) 6877c478bd9Sstevel@tonic-gate return; 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate ds->cb_hrtime = (a->cb_hrtime > b->cb_hrtime) ? 6907c478bd9Sstevel@tonic-gate a->cb_hrtime : b->cb_hrtime; 6917c478bd9Sstevel@tonic-gate ds->cb_tick = a->cb_tick + b->cb_tick; 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate for (i = 0; i < ds->cb_size / sizeof (uint64_t); i++) 6947c478bd9Sstevel@tonic-gate ds->cb_data[i] = a->cb_data[i] + b->cb_data[i]; 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6987c478bd9Sstevel@tonic-gate void 6997c478bd9Sstevel@tonic-gate cpc_buf_copy(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *src) 7007c478bd9Sstevel@tonic-gate { 7017c478bd9Sstevel@tonic-gate if (ds->cb_size != src->cb_size) 7027c478bd9Sstevel@tonic-gate return; 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate bcopy(src->cb_data, ds->cb_data, ds->cb_size); 7057c478bd9Sstevel@tonic-gate ds->cb_hrtime = src->cb_hrtime; 7067c478bd9Sstevel@tonic-gate ds->cb_tick = src->cb_tick; 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7107c478bd9Sstevel@tonic-gate void 7117c478bd9Sstevel@tonic-gate cpc_buf_zero(cpc_t *cpc, cpc_buf_t *buf) 7127c478bd9Sstevel@tonic-gate { 7137c478bd9Sstevel@tonic-gate bzero(buf->cb_data, buf->cb_size); 7147c478bd9Sstevel@tonic-gate buf->cb_hrtime = 0; 7157c478bd9Sstevel@tonic-gate buf->cb_tick = 0; 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate /* 7197c478bd9Sstevel@tonic-gate * Gets or sets the value of the request specified by index. 7207c478bd9Sstevel@tonic-gate */ 7217c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7227c478bd9Sstevel@tonic-gate int 7237c478bd9Sstevel@tonic-gate cpc_buf_get(cpc_t *cpc, cpc_buf_t *buf, int index, uint64_t *val) 7247c478bd9Sstevel@tonic-gate { 7257c478bd9Sstevel@tonic-gate *val = buf->cb_data[index]; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate return (0); 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7317c478bd9Sstevel@tonic-gate int 7327c478bd9Sstevel@tonic-gate cpc_buf_set(cpc_t *cpc, cpc_buf_t *buf, int index, uint64_t val) 7337c478bd9Sstevel@tonic-gate { 7347c478bd9Sstevel@tonic-gate buf->cb_data[index] = val; 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate return (0); 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7407c478bd9Sstevel@tonic-gate hrtime_t 7417c478bd9Sstevel@tonic-gate cpc_buf_hrtime(cpc_t *cpc, cpc_buf_t *buf) 7427c478bd9Sstevel@tonic-gate { 7437c478bd9Sstevel@tonic-gate return (buf->cb_hrtime); 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7477c478bd9Sstevel@tonic-gate uint64_t 7487c478bd9Sstevel@tonic-gate cpc_buf_tick(cpc_t *cpc, cpc_buf_t *buf) 7497c478bd9Sstevel@tonic-gate { 7507c478bd9Sstevel@tonic-gate return (buf->cb_tick); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate static char * 7547c478bd9Sstevel@tonic-gate cpc_get_list(int which, int arg) 7557c478bd9Sstevel@tonic-gate { 7567c478bd9Sstevel@tonic-gate int szcmd; 7577c478bd9Sstevel@tonic-gate int size; 7587c478bd9Sstevel@tonic-gate char *list; 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate if (which == CPC_LIST_ATTRS) 7617c478bd9Sstevel@tonic-gate szcmd = CPC_ATTRLIST_SIZE; 7627c478bd9Sstevel@tonic-gate else 7637c478bd9Sstevel@tonic-gate szcmd = CPC_EVLIST_SIZE; 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, szcmd, -1, &size, arg, 0) != 0) 7667c478bd9Sstevel@tonic-gate return (NULL); 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate if ((list = malloc(size)) == NULL) 7697c478bd9Sstevel@tonic-gate return (NULL); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, which, -1, list, arg, 0) != 0) { 7727c478bd9Sstevel@tonic-gate free(list); 7737c478bd9Sstevel@tonic-gate return (NULL); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate return (list); 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7807c478bd9Sstevel@tonic-gate void 7817c478bd9Sstevel@tonic-gate cpc_walk_requests(cpc_t *cpc, cpc_set_t *set, void *arg, 7827c478bd9Sstevel@tonic-gate void (*action)(void *arg, int index, const char *event, uint64_t preset, 7837c478bd9Sstevel@tonic-gate uint_t flags, int nattrs, const cpc_attr_t *attrs)) 7847c478bd9Sstevel@tonic-gate { 7857c478bd9Sstevel@tonic-gate cpc_request_t *rp; 7867c478bd9Sstevel@tonic-gate cpc_attr_t *attrs = NULL; 7877c478bd9Sstevel@tonic-gate int i; 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate for (rp = set->cs_request; rp != NULL; rp = rp->cr_next) { 7907c478bd9Sstevel@tonic-gate /* 7917c478bd9Sstevel@tonic-gate * Need to reconstruct a temporary cpc_attr_t array for req. 7927c478bd9Sstevel@tonic-gate */ 7937c478bd9Sstevel@tonic-gate if (rp->cr_nattrs != 0) 7947c478bd9Sstevel@tonic-gate if ((attrs = malloc(rp->cr_nattrs * 7957c478bd9Sstevel@tonic-gate sizeof (cpc_attr_t))) == NULL) 7967c478bd9Sstevel@tonic-gate return; 7977c478bd9Sstevel@tonic-gate for (i = 0; i < rp->cr_nattrs; i++) { 7987c478bd9Sstevel@tonic-gate attrs[i].ca_name = rp->cr_attr[i].ka_name; 7997c478bd9Sstevel@tonic-gate attrs[i].ca_val = rp->cr_attr[i].ka_val; 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate action(arg, rp->cr_index, rp->cr_event, rp->cr_preset, 8037c478bd9Sstevel@tonic-gate rp->cr_flags, rp->cr_nattrs, attrs); 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate if (rp->cr_nattrs != 0) 8067c478bd9Sstevel@tonic-gate free(attrs); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 811e850fb01SKuriakose Kuruvilla static void 812e850fb01SKuriakose Kuruvilla cpc_walk_events_impl(cpc_t *cpc, void *arg, 813e850fb01SKuriakose Kuruvilla void (*action)(void *arg, const char *event), int is_generic) 8147c478bd9Sstevel@tonic-gate { 8157c478bd9Sstevel@tonic-gate char **list; 8167c478bd9Sstevel@tonic-gate char *p, *e; 8177c478bd9Sstevel@tonic-gate int i; 818e850fb01SKuriakose Kuruvilla int is_papi; 8197c478bd9Sstevel@tonic-gate int ncounters = cpc_npic(cpc); 8207c478bd9Sstevel@tonic-gate cpc_strhash_t *hash; 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate if ((list = malloc(ncounters * sizeof (char *))) == NULL) 8237c478bd9Sstevel@tonic-gate return; 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate if ((hash = __cpc_strhash_alloc()) == NULL) { 8267c478bd9Sstevel@tonic-gate free(list); 8277c478bd9Sstevel@tonic-gate return; 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 8317c478bd9Sstevel@tonic-gate if ((list[i] = strdup(cpc->cpc_evlist[i])) == NULL) 8327c478bd9Sstevel@tonic-gate goto err; 8337c478bd9Sstevel@tonic-gate p = list[i]; 8347c478bd9Sstevel@tonic-gate while ((e = strchr(p, ',')) != NULL) { 8357c478bd9Sstevel@tonic-gate *e = '\0'; 836c7a079a8SJonathan Haslam 837e850fb01SKuriakose Kuruvilla /* 838e850fb01SKuriakose Kuruvilla * Based on is_generic flag, skip appropriate 839e850fb01SKuriakose Kuruvilla * event names. 840e850fb01SKuriakose Kuruvilla */ 841e850fb01SKuriakose Kuruvilla is_papi = (strncmp(p, "PAPI", 4) == 0); 842e850fb01SKuriakose Kuruvilla if (is_generic != is_papi) { 843c7a079a8SJonathan Haslam p = e + 1; 844c7a079a8SJonathan Haslam continue; 845c7a079a8SJonathan Haslam } 846c7a079a8SJonathan Haslam 8477c478bd9Sstevel@tonic-gate if (__cpc_strhash_add(hash, p) == -1) 8487c478bd9Sstevel@tonic-gate goto err; 849e850fb01SKuriakose Kuruvilla 8507c478bd9Sstevel@tonic-gate p = e + 1; 8517c478bd9Sstevel@tonic-gate } 852e850fb01SKuriakose Kuruvilla 853e850fb01SKuriakose Kuruvilla is_papi = (strncmp(p, "PAPI", 4) == 0); 854e850fb01SKuriakose Kuruvilla if (is_generic == is_papi) { 8557c478bd9Sstevel@tonic-gate if (__cpc_strhash_add(hash, p) == -1) 8567c478bd9Sstevel@tonic-gate goto err; 8577c478bd9Sstevel@tonic-gate } 858c7a079a8SJonathan Haslam } 859c7a079a8SJonathan Haslam 860c7a079a8SJonathan Haslam while ((p = __cpc_strhash_next(hash)) != NULL) 861c7a079a8SJonathan Haslam action(arg, p); 862c7a079a8SJonathan Haslam 863c7a079a8SJonathan Haslam err: 864c7a079a8SJonathan Haslam __cpc_strhash_free(hash); 865c7a079a8SJonathan Haslam for (i = 0; i < ncounters; i++) 866c7a079a8SJonathan Haslam free(list[i]); 867c7a079a8SJonathan Haslam free(list); 868c7a079a8SJonathan Haslam } 869c7a079a8SJonathan Haslam 870c7a079a8SJonathan Haslam /*ARGSUSED*/ 871c7a079a8SJonathan Haslam void 872e850fb01SKuriakose Kuruvilla cpc_walk_events_all(cpc_t *cpc, void *arg, 873e850fb01SKuriakose Kuruvilla void (*action)(void *arg, const char *event)) 874e850fb01SKuriakose Kuruvilla { 875e850fb01SKuriakose Kuruvilla cpc_walk_events_impl(cpc, arg, action, 0); 876e850fb01SKuriakose Kuruvilla } 877e850fb01SKuriakose Kuruvilla 878e850fb01SKuriakose Kuruvilla 879e850fb01SKuriakose Kuruvilla /*ARGSUSED*/ 880e850fb01SKuriakose Kuruvilla void 881c7a079a8SJonathan Haslam cpc_walk_generic_events_all(cpc_t *cpc, void *arg, 882c7a079a8SJonathan Haslam void (*action)(void *arg, const char *event)) 883c7a079a8SJonathan Haslam { 884e850fb01SKuriakose Kuruvilla cpc_walk_events_impl(cpc, arg, action, 1); 885e850fb01SKuriakose Kuruvilla } 886c7a079a8SJonathan Haslam 887e850fb01SKuriakose Kuruvilla /*ARGSUSED*/ 888e850fb01SKuriakose Kuruvilla static void 889e850fb01SKuriakose Kuruvilla cpc_walk_events_pic_impl(cpc_t *cpc, uint_t picno, void *arg, 890e850fb01SKuriakose Kuruvilla void (*action)(void *arg, uint_t picno, const char *event), int is_generic) 891e850fb01SKuriakose Kuruvilla { 892e850fb01SKuriakose Kuruvilla char *p; 893e850fb01SKuriakose Kuruvilla char *e; 894e850fb01SKuriakose Kuruvilla char *list; 895e850fb01SKuriakose Kuruvilla int is_papi; 896c7a079a8SJonathan Haslam 897e850fb01SKuriakose Kuruvilla if (picno >= cpc->cpc_npic) { 898e850fb01SKuriakose Kuruvilla errno = EINVAL; 899c7a079a8SJonathan Haslam return; 900c7a079a8SJonathan Haslam } 901c7a079a8SJonathan Haslam 902e850fb01SKuriakose Kuruvilla if ((list = strdup(cpc->cpc_evlist[picno])) == NULL) 903e850fb01SKuriakose Kuruvilla return; 904e850fb01SKuriakose Kuruvilla 905e850fb01SKuriakose Kuruvilla /* 906e850fb01SKuriakose Kuruvilla * List now points to a comma-separated list of events supported by 907e850fb01SKuriakose Kuruvilla * the designated pic. 908e850fb01SKuriakose Kuruvilla */ 909e850fb01SKuriakose Kuruvilla p = list; 910c7a079a8SJonathan Haslam while ((e = strchr(p, ',')) != NULL) { 911c7a079a8SJonathan Haslam *e = '\0'; 912c7a079a8SJonathan Haslam 913e850fb01SKuriakose Kuruvilla /* 914e850fb01SKuriakose Kuruvilla * Based on is_generic flag, skip appropriate 915e850fb01SKuriakose Kuruvilla * event names. 916e850fb01SKuriakose Kuruvilla */ 917e850fb01SKuriakose Kuruvilla is_papi = (strncmp(p, "PAPI", 4) == 0); 918e850fb01SKuriakose Kuruvilla if (is_generic != is_papi) { 919c7a079a8SJonathan Haslam p = e + 1; 920c7a079a8SJonathan Haslam continue; 921c7a079a8SJonathan Haslam } 922c7a079a8SJonathan Haslam 923e850fb01SKuriakose Kuruvilla action(arg, picno, p); 924c7a079a8SJonathan Haslam p = e + 1; 925c7a079a8SJonathan Haslam } 9267c478bd9Sstevel@tonic-gate 927e850fb01SKuriakose Kuruvilla is_papi = (strncmp(p, "PAPI", 4) == 0); 928e850fb01SKuriakose Kuruvilla if (is_generic == is_papi) 929e850fb01SKuriakose Kuruvilla action(arg, picno, p); 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate free(list); 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9357c478bd9Sstevel@tonic-gate void 9367c478bd9Sstevel@tonic-gate cpc_walk_events_pic(cpc_t *cpc, uint_t picno, void *arg, 9377c478bd9Sstevel@tonic-gate void (*action)(void *arg, uint_t picno, const char *event)) 9387c478bd9Sstevel@tonic-gate { 939e850fb01SKuriakose Kuruvilla cpc_walk_events_pic_impl(cpc, picno, arg, action, 0); 940c7a079a8SJonathan Haslam } 941c7a079a8SJonathan Haslam 942c7a079a8SJonathan Haslam /*ARGSUSED*/ 943c7a079a8SJonathan Haslam void 944c7a079a8SJonathan Haslam cpc_walk_generic_events_pic(cpc_t *cpc, uint_t picno, void *arg, 945c7a079a8SJonathan Haslam void (*action)(void *arg, uint_t picno, const char *event)) 946c7a079a8SJonathan Haslam { 947e850fb01SKuriakose Kuruvilla cpc_walk_events_pic_impl(cpc, picno, arg, action, 1); 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9517c478bd9Sstevel@tonic-gate void 9527c478bd9Sstevel@tonic-gate cpc_walk_attrs(cpc_t *cpc, void *arg, 9537c478bd9Sstevel@tonic-gate void (*action)(void *arg, const char *attr)) 9547c478bd9Sstevel@tonic-gate { 9557c478bd9Sstevel@tonic-gate char *p; 9567c478bd9Sstevel@tonic-gate char *e; 9577c478bd9Sstevel@tonic-gate char *list; 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate if ((list = strdup(cpc->cpc_attrlist)) == NULL) 9607c478bd9Sstevel@tonic-gate return; 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate /* 9637c478bd9Sstevel@tonic-gate * Platforms with no attributes will return an empty string. 9647c478bd9Sstevel@tonic-gate */ 9657c478bd9Sstevel@tonic-gate if (*list == '\0') 9667c478bd9Sstevel@tonic-gate return; 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate /* 9697c478bd9Sstevel@tonic-gate * List now points to a comma-separated list of attributes supported by 9707c478bd9Sstevel@tonic-gate * the underlying platform. 9717c478bd9Sstevel@tonic-gate */ 9727c478bd9Sstevel@tonic-gate p = list; 9737c478bd9Sstevel@tonic-gate while ((e = strchr(p, ',')) != NULL) { 9747c478bd9Sstevel@tonic-gate *e = '\0'; 9757c478bd9Sstevel@tonic-gate action(arg, p); 9767c478bd9Sstevel@tonic-gate p = e + 1; 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate action(arg, p); 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate free(list); 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9847c478bd9Sstevel@tonic-gate int 9857c478bd9Sstevel@tonic-gate cpc_enable(cpc_t *cpc) 9867c478bd9Sstevel@tonic-gate { 9877c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_ENABLE, -1, 0, 0, 0)); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9917c478bd9Sstevel@tonic-gate int 9927c478bd9Sstevel@tonic-gate cpc_disable(cpc_t *cpc) 9937c478bd9Sstevel@tonic-gate { 9947c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_DISABLE, -1, 0, 0, 0)); 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9987c478bd9Sstevel@tonic-gate uint_t 9997c478bd9Sstevel@tonic-gate cpc_npic(cpc_t *cpc) 10007c478bd9Sstevel@tonic-gate { 10017c478bd9Sstevel@tonic-gate return (cpc->cpc_npic); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10057c478bd9Sstevel@tonic-gate uint_t 10067c478bd9Sstevel@tonic-gate cpc_caps(cpc_t *cpc) 10077c478bd9Sstevel@tonic-gate { 10087c478bd9Sstevel@tonic-gate return (cpc->cpc_caps); 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate const char * 10127c478bd9Sstevel@tonic-gate cpc_cciname(cpc_t *cpc) 10137c478bd9Sstevel@tonic-gate { 10147c478bd9Sstevel@tonic-gate return (cpc->cpc_cciname); 10157c478bd9Sstevel@tonic-gate } 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate const char * 10187c478bd9Sstevel@tonic-gate cpc_cpuref(cpc_t *cpc) 10197c478bd9Sstevel@tonic-gate { 10207c478bd9Sstevel@tonic-gate return (cpc->cpc_cpuref); 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate int 10247c478bd9Sstevel@tonic-gate cpc_seterrhndlr(cpc_t *cpc, cpc_errhndlr_t *fn) 10257c478bd9Sstevel@tonic-gate { 10267c478bd9Sstevel@tonic-gate cpc->cpc_errfn = fn; 10277c478bd9Sstevel@tonic-gate return (0); 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate /* 10317c478bd9Sstevel@tonic-gate * These strings may contain printf() conversion specifiers. 10327c478bd9Sstevel@tonic-gate */ 10337c478bd9Sstevel@tonic-gate static const char *errstr[] = { 10347c478bd9Sstevel@tonic-gate "", /* zero slot filler */ 10357c478bd9Sstevel@tonic-gate "Unknown event\n", /* CPC_INVALID_EVENT */ 10367c478bd9Sstevel@tonic-gate "Invalid counter number\n", /* CPC_INVALID_PICNUM */ 10377c478bd9Sstevel@tonic-gate "Unknown attribute\n", /* CPC_INVALID_ATTRIBUTE */ 10387c478bd9Sstevel@tonic-gate "Attribute out of range\n", /* CPC_ATTRIBUTE_OUT_OF_RANGE */ 10397c478bd9Sstevel@tonic-gate "Hardware resource unavailable\n", /* CPC_RESOURCE_UNAVAIL */ 10407c478bd9Sstevel@tonic-gate "Counter cannot count requested event\n", /* CPC_PIC_NOT_CAPABLE */ 10417c478bd9Sstevel@tonic-gate "Invalid flags in a request\n", /* CPC_REQ_INVALID_FLAGS */ 10427c478bd9Sstevel@tonic-gate "Requests conflict with each other\n", /* CPC_CONFLICTING_REQS */ 10437c478bd9Sstevel@tonic-gate "Attribute requires the cpc_cpu privilege\n", /* CPC_ATTR_REQUIRES_PRIVILEGE */ 10448d4e547dSae112802 "Couldn't bind LWP to requested processor\n", /* CPC_PBIND_FAILED */ 10458d4e547dSae112802 "Hypervisor event access denied\n" /* CPC_HV_NO_ACCESS */ 10467c478bd9Sstevel@tonic-gate }; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate /*VARARGS3*/ 10497c478bd9Sstevel@tonic-gate static void 10507c478bd9Sstevel@tonic-gate cpc_err(cpc_t *cpc, const char *fn, int subcode, ...) 10517c478bd9Sstevel@tonic-gate { 10527c478bd9Sstevel@tonic-gate va_list ap; 10537c478bd9Sstevel@tonic-gate const char *str; 10547c478bd9Sstevel@tonic-gate int error; 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate /* 10577c478bd9Sstevel@tonic-gate * If subcode is -1, there is no specific description for this error. 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate if (subcode == -1) 10607c478bd9Sstevel@tonic-gate return; 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate /* 10637c478bd9Sstevel@tonic-gate * We need to preserve errno across calls to this function to prevent it 10647c478bd9Sstevel@tonic-gate * from being clobbered while here, or in the user's error handler. 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate error = errno; 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate str = dgettext(TEXT_DOMAIN, errstr[subcode]); 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate va_start(ap, subcode); 10717c478bd9Sstevel@tonic-gate if (cpc->cpc_errfn != NULL) 10727c478bd9Sstevel@tonic-gate cpc->cpc_errfn(fn, subcode, str, ap); 10737c478bd9Sstevel@tonic-gate else { 10747c478bd9Sstevel@tonic-gate /* 10757c478bd9Sstevel@tonic-gate * If printf() conversion specifiers are added to the errstr[] 10767c478bd9Sstevel@tonic-gate * table, this call needs to be changed to vfprintf(). 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "libcpc: %s: %s", fn, str); 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate va_end(ap); 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate errno = error; 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate /* 10867c478bd9Sstevel@tonic-gate * Hook used by libpctx to alert libcpc when a pctx handle is going away. 10877c478bd9Sstevel@tonic-gate * This is necessary to prevent libcpc from attempting a libpctx operation on a 10887c478bd9Sstevel@tonic-gate * stale and invalid pctx_t handle. Since pctx_t's are cached by libcpc, we need 10897c478bd9Sstevel@tonic-gate * to be notified when they go away. 10907c478bd9Sstevel@tonic-gate */ 10917c478bd9Sstevel@tonic-gate static void 10927c478bd9Sstevel@tonic-gate cpc_invalidate_pctx(cpc_t *cpc, pctx_t *pctx) 10937c478bd9Sstevel@tonic-gate { 10947c478bd9Sstevel@tonic-gate cpc_set_t *set; 10957c478bd9Sstevel@tonic-gate int sigblocked; 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 10987c478bd9Sstevel@tonic-gate for (set = cpc->cpc_sets; set != NULL; set = set->cs_next) 10997c478bd9Sstevel@tonic-gate if (set->cs_pctx == pctx) 11007c478bd9Sstevel@tonic-gate set->cs_pctx = NULL; 11017c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate /* 11057c478bd9Sstevel@tonic-gate * Check that the set is valid; if so it will be in the cpc handle's 11067c478bd9Sstevel@tonic-gate * list of sets. The lock protects the list of sets, but not the set 11077c478bd9Sstevel@tonic-gate * itself. 11087c478bd9Sstevel@tonic-gate */ 11097c478bd9Sstevel@tonic-gate static int 11107c478bd9Sstevel@tonic-gate cpc_set_valid(cpc_t *cpc, cpc_set_t *set) 11117c478bd9Sstevel@tonic-gate { 11127c478bd9Sstevel@tonic-gate cpc_set_t *csp; 11137c478bd9Sstevel@tonic-gate int sigblocked; 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 11167c478bd9Sstevel@tonic-gate for (csp = cpc->cpc_sets; csp != NULL; csp = csp->cs_next) 11177c478bd9Sstevel@tonic-gate if (csp == set) 11187c478bd9Sstevel@tonic-gate break; 11197c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 11207c478bd9Sstevel@tonic-gate if (csp == NULL) 11217c478bd9Sstevel@tonic-gate return (-1); 11227c478bd9Sstevel@tonic-gate return (0); 11237c478bd9Sstevel@tonic-gate } 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate static int 11267c478bd9Sstevel@tonic-gate cpc_lock(cpc_t *cpc) 11277c478bd9Sstevel@tonic-gate { 11287c478bd9Sstevel@tonic-gate int ret = (sigset(SIGEMT, SIG_HOLD) == SIG_HOLD); 11297c478bd9Sstevel@tonic-gate (void) mutex_lock(&cpc->cpc_lock); 11307c478bd9Sstevel@tonic-gate return (ret); 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate static void 11347c478bd9Sstevel@tonic-gate cpc_unlock(cpc_t *cpc, int sigblocked) 11357c478bd9Sstevel@tonic-gate { 11367c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cpc->cpc_lock); 11377c478bd9Sstevel@tonic-gate if (sigblocked == 0) 11387c478bd9Sstevel@tonic-gate (void) sigrelse(SIGEMT); 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate struct priv { 11427c478bd9Sstevel@tonic-gate const char *name; 11437c478bd9Sstevel@tonic-gate int found; 11447c478bd9Sstevel@tonic-gate }; 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11477c478bd9Sstevel@tonic-gate static void 11487c478bd9Sstevel@tonic-gate ev_walker(void *arg, uint_t picno, const char *ev) 11497c478bd9Sstevel@tonic-gate { 11507c478bd9Sstevel@tonic-gate if (strcmp(((struct priv *)arg)->name, ev) == 0) 11517c478bd9Sstevel@tonic-gate ((struct priv *)arg)->found = 1; 11527c478bd9Sstevel@tonic-gate } 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate static void 11557c478bd9Sstevel@tonic-gate at_walker(void *arg, const char *at) 11567c478bd9Sstevel@tonic-gate { 11577c478bd9Sstevel@tonic-gate if (strcmp(((struct priv *)arg)->name, at) == 0) 11587c478bd9Sstevel@tonic-gate ((struct priv *)arg)->found = 1; 11597c478bd9Sstevel@tonic-gate } 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate static int 11627c478bd9Sstevel@tonic-gate cpc_valid_event(cpc_t *cpc, uint_t pic, const char *ev) 11637c478bd9Sstevel@tonic-gate { 11647c478bd9Sstevel@tonic-gate struct priv pr = { NULL, 0 }; 1165d0ecda70Svk226950 char *end_ev; 1166e850fb01SKuriakose Kuruvilla int err; 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate pr.name = ev; 11697c478bd9Sstevel@tonic-gate cpc_walk_events_pic(cpc, pic, &pr, ev_walker); 11705d3a5ad8Srab if (pr.found) 11715d3a5ad8Srab return (1); 11725d3a5ad8Srab 1173c7a079a8SJonathan Haslam cpc_walk_generic_events_pic(cpc, pic, &pr, ev_walker); 1174c7a079a8SJonathan Haslam if (pr.found) 1175c7a079a8SJonathan Haslam return (1); 1176c7a079a8SJonathan Haslam 11775d3a5ad8Srab /* 11785d3a5ad8Srab * Before assuming this is an invalid event, see if we have been given 1179e850fb01SKuriakose Kuruvilla * a raw event code. 1180d0ecda70Svk226950 * Check the second argument of strtol() to ensure invalid events 1181d0ecda70Svk226950 * beginning with number do not go through. 11825d3a5ad8Srab */ 1183e850fb01SKuriakose Kuruvilla err = errno; 1184e850fb01SKuriakose Kuruvilla errno = 0; 1185e850fb01SKuriakose Kuruvilla (void) strtol(ev, &end_ev, 0); 1186e850fb01SKuriakose Kuruvilla if ((errno == 0) && (*end_ev == '\0')) { 11875d3a5ad8Srab /* 11885d3a5ad8Srab * Success - this is a valid raw code in hex, decimal, or octal. 11895d3a5ad8Srab */ 1190e850fb01SKuriakose Kuruvilla errno = err; 11915d3a5ad8Srab return (1); 1192e850fb01SKuriakose Kuruvilla } 11935d3a5ad8Srab 1194e850fb01SKuriakose Kuruvilla errno = err; 11955d3a5ad8Srab return (0); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate static int 11997c478bd9Sstevel@tonic-gate cpc_valid_attr(cpc_t *cpc, char *attr) 12007c478bd9Sstevel@tonic-gate { 12017c478bd9Sstevel@tonic-gate struct priv pr = { NULL, 0 }; 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate pr.name = attr; 12047c478bd9Sstevel@tonic-gate cpc_walk_attrs(cpc, &pr, at_walker); 12057c478bd9Sstevel@tonic-gate return (pr.found); 12067c478bd9Sstevel@tonic-gate } 1207