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