Module Name: src Committed By: snj Date: Tue Aug 1 23:18:31 UTC 2017
Modified Files: src/distrib/sets/lists/base [netbsd-8]: md.amd64 src/distrib/sets/lists/debug [netbsd-8]: md.amd64 src/sys/arch/amd64/conf [netbsd-8]: GENERIC files.amd64 src/sys/arch/i386/conf [netbsd-8]: GENERIC files.i386 src/sys/arch/i386/i386 [netbsd-8]: i386_trap.S src/sys/arch/i386/include [netbsd-8]: frameasm.h src/sys/arch/x86/include [netbsd-8]: sysarch.h src/sys/arch/x86/x86 [netbsd-8]: pmc.c sys_machdep.c src/sys/arch/xen/conf [netbsd-8]: files.compat src/sys/secmodel/suser [netbsd-8]: secmodel_suser.c src/sys/sys [netbsd-8]: kauth.h src/usr.bin/pmc [netbsd-8]: Makefile pmc.1 pmc.c Log Message: Pull up following revision(s) (requested by maxv in ticket #164): distrib/sets/lists/base/md.amd64: revision 1.269 distrib/sets/lists/debug/md.amd64: revision 1.97 sys/arch/amd64/conf/GENERIC: revision 1.460 sys/arch/amd64/conf/files.amd64: revision 1.89 sys/arch/i386/conf/GENERIC: revision 1.1157 sys/arch/i386/conf/files.i386: revision 1.379 sys/arch/i386/i386/i386_trap.S: revision 1.7-1.8 sys/arch/i386/include/frameasm.h: revision 1.16 sys/arch/x86/include/sysarch.h: revision 1.12 sys/arch/x86/x86/pmc.c: revision 1.8-1.10 sys/arch/x86/x86/sys_machdep.c: revision 1.36 sys/arch/xen/conf/files.compat: revision 1.26 sys/secmodel/suser/secmodel_suser.c: revision 1.43 sys/sys/kauth.h: revision 1.74 usr.bin/pmc/Makefile: revision 1.5 usr.bin/pmc/pmc.1: revision 1.12-1.13 usr.bin/pmc/pmc.c: revision 1.24-1.25 style -- style -- Disable interrupts for T_NMI (inline calltrap). Note that there's still a way to evade the NMI mode here, if a segment register faults in INTRFASTEXIT; but we don't care. I didn't test this change, but it seems fine enough. -- Make the PMC syscalls privileged. -- Check argc, and add a message. -- include opt_pmc.h -- Build the pmc tool on amd64. -- Properly handle overflows, and take them into account in userland. -- Update. -- Enable PMCs by default. -- Sort sections. Fix macro usage. To generate a diff of this commit: cvs rdiff -u -r1.268 -r1.268.4.1 src/distrib/sets/lists/base/md.amd64 cvs rdiff -u -r1.96 -r1.96.2.1 src/distrib/sets/lists/debug/md.amd64 cvs rdiff -u -r1.459.2.1 -r1.459.2.2 src/sys/arch/amd64/conf/GENERIC cvs rdiff -u -r1.88 -r1.88.8.1 src/sys/arch/amd64/conf/files.amd64 cvs rdiff -u -r1.1156.2.1 -r1.1156.2.2 src/sys/arch/i386/conf/GENERIC cvs rdiff -u -r1.378 -r1.378.6.1 src/sys/arch/i386/conf/files.i386 cvs rdiff -u -r1.6 -r1.6.6.1 src/sys/arch/i386/i386/i386_trap.S cvs rdiff -u -r1.15 -r1.15.46.1 src/sys/arch/i386/include/frameasm.h cvs rdiff -u -r1.11 -r1.11.6.1 src/sys/arch/x86/include/sysarch.h cvs rdiff -u -r1.7 -r1.7.2.1 src/sys/arch/x86/x86/pmc.c cvs rdiff -u -r1.35 -r1.35.6.1 src/sys/arch/x86/x86/sys_machdep.c cvs rdiff -u -r1.25 -r1.25.8.1 src/sys/arch/xen/conf/files.compat cvs rdiff -u -r1.42 -r1.42.10.1 src/sys/secmodel/suser/secmodel_suser.c cvs rdiff -u -r1.73 -r1.73.10.1 src/sys/sys/kauth.h cvs rdiff -u -r1.4 -r1.4.4.1 src/usr.bin/pmc/Makefile cvs rdiff -u -r1.11 -r1.11.4.1 src/usr.bin/pmc/pmc.1 cvs rdiff -u -r1.23 -r1.23.4.1 src/usr.bin/pmc/pmc.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/base/md.amd64 diff -u src/distrib/sets/lists/base/md.amd64:1.268 src/distrib/sets/lists/base/md.amd64:1.268.4.1 --- src/distrib/sets/lists/base/md.amd64:1.268 Tue Jan 24 11:09:14 2017 +++ src/distrib/sets/lists/base/md.amd64 Tue Aug 1 23:18:30 2017 @@ -1,9 +1,10 @@ -# $NetBSD: md.amd64,v 1.268 2017/01/24 11:09:14 nonaka Exp $ +# $NetBSD: md.amd64,v 1.268.4.1 2017/08/01 23:18:30 snj Exp $ ./dev/lms0 base-obsolete obsolete ./dev/mms0 base-obsolete obsolete ./libexec/ld.elf_so-i386 base-sys-shlib compat,pic ./usr/bin/fdformat base-util-bin ./usr/bin/iasl base-util-bin +./usr/bin/pmc base-util-bin ./usr/lib/i386/libi386.so.1 base-compat-shlib compat,pic ./usr/lib/i386/libi386.so.1.0 base-compat-shlib compat,pic ./usr/lib/i386/libproc.so.0 base-compat-shlib compat,pic,dtrace Index: src/distrib/sets/lists/debug/md.amd64 diff -u src/distrib/sets/lists/debug/md.amd64:1.96 src/distrib/sets/lists/debug/md.amd64:1.96.2.1 --- src/distrib/sets/lists/debug/md.amd64:1.96 Sun May 7 02:05:56 2017 +++ src/distrib/sets/lists/debug/md.amd64 Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -# $NetBSD: md.amd64,v 1.96 2017/05/07 02:05:56 kamil Exp $ +# $NetBSD: md.amd64,v 1.96.2.1 2017/08/01 23:18:30 snj Exp $ ./usr/lib/i386/12.202++_g.a comp-c-debuglib debuglib,compat,12.202xx ./usr/lib/i386/libi386_g.a comp-c-debuglib debuglib,compat ./usr/lib/i386/libiberty_g.a comp-obsolete obsolete @@ -6,6 +6,7 @@ ./usr/libdata/debug/libexec/ld.elf_so-i386.debug comp-sys-debug debug,compat ./usr/libdata/debug/usr/bin/fdformat.debug comp-util-debug debug ./usr/libdata/debug/usr/bin/iasl.debug comp-util-debug debug +./usr/libdata/debug/usr/bin/pmc.debug comp-util-debug debug ./usr/libdata/debug/usr/lib/i386/libi386.so.1.0.debug comp-compat-shlib compat,pic,debug ./usr/libdata/debug/usr/lib/i386/libpam.so.4.1.debug comp-compat-shlib compat,pic,debug,pam ./usr/libdata/debug/usr/lib/i386/libproc.so.0.0.debug comp-compat-shlib compat,pic,debug,dtrace Index: src/sys/arch/amd64/conf/GENERIC diff -u src/sys/arch/amd64/conf/GENERIC:1.459.2.1 src/sys/arch/amd64/conf/GENERIC:1.459.2.2 --- src/sys/arch/amd64/conf/GENERIC:1.459.2.1 Wed Jul 5 13:58:48 2017 +++ src/sys/arch/amd64/conf/GENERIC Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -# $NetBSD: GENERIC,v 1.459.2.1 2017/07/05 13:58:48 martin Exp $ +# $NetBSD: GENERIC,v 1.459.2.2 2017/08/01 23:18:30 snj Exp $ # # GENERIC machine description file # @@ -22,7 +22,7 @@ include "arch/amd64/conf/std.amd64" options INCLUDE_CONFIG_FILE # embed config file in kernel binary -#ident "GENERIC-$Revision: 1.459.2.1 $" +#ident "GENERIC-$Revision: 1.459.2.2 $" maxusers 64 # estimated number of users @@ -81,7 +81,7 @@ est0 at cpu0 # Intel Enhanced SpeedSte powernow0 at cpu0 # AMD PowerNow! and Cool'n'Quiet (non-ACPI) vmt0 at cpu0 # VMware Tools -#options PMC # performance-monitoring counters support +options PMC # performance-monitoring counters support # Alternate buffer queue strategies for better responsiveness under high # disk I/O load. Index: src/sys/arch/amd64/conf/files.amd64 diff -u src/sys/arch/amd64/conf/files.amd64:1.88 src/sys/arch/amd64/conf/files.amd64:1.88.8.1 --- src/sys/arch/amd64/conf/files.amd64:1.88 Thu Dec 15 12:04:17 2016 +++ src/sys/arch/amd64/conf/files.amd64 Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -# $NetBSD: files.amd64,v 1.88 2016/12/15 12:04:17 kamil Exp $ +# $NetBSD: files.amd64,v 1.88.8.1 2017/08/01 23:18:30 snj Exp $ # # new style config file for amd64 architecture # @@ -24,6 +24,7 @@ defparam opt_physmem.h PHYSMEM_MAX_ADDR # with the i386 (they include the opt_*.h for these) # +defflag PMC defflag USER_LDT defflag eisa.h EISA Index: src/sys/arch/i386/conf/GENERIC diff -u src/sys/arch/i386/conf/GENERIC:1.1156.2.1 src/sys/arch/i386/conf/GENERIC:1.1156.2.2 --- src/sys/arch/i386/conf/GENERIC:1.1156.2.1 Wed Jul 5 13:58:48 2017 +++ src/sys/arch/i386/conf/GENERIC Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -# $NetBSD: GENERIC,v 1.1156.2.1 2017/07/05 13:58:48 martin Exp $ +# $NetBSD: GENERIC,v 1.1156.2.2 2017/08/01 23:18:30 snj Exp $ # # GENERIC machine description file # @@ -22,7 +22,7 @@ include "arch/i386/conf/std.i386" options INCLUDE_CONFIG_FILE # embed config file in kernel binary -#ident "GENERIC-$Revision: 1.1156.2.1 $" +#ident "GENERIC-$Revision: 1.1156.2.2 $" maxusers 64 # estimated number of users @@ -42,7 +42,7 @@ viac7temp* at cpu? # VIA C7 temperature vmt0 at cpu0 # VMware Tools options MTRR # memory-type range register syscall support -#options PMC # performance-monitoring counters support +options PMC # performance-monitoring counters support options MULTIBOOT # Multiboot support (see multiboot(8)) Index: src/sys/arch/i386/conf/files.i386 diff -u src/sys/arch/i386/conf/files.i386:1.378 src/sys/arch/i386/conf/files.i386:1.378.6.1 --- src/sys/arch/i386/conf/files.i386:1.378 Fri Mar 10 14:40:56 2017 +++ src/sys/arch/i386/conf/files.i386 Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -# $NetBSD: files.i386,v 1.378 2017/03/10 14:40:56 maxv Exp $ +# $NetBSD: files.i386,v 1.378.6.1 2017/08/01 23:18:30 snj Exp $ # # new style config file for i386 architecture # @@ -21,6 +21,8 @@ obsolete defflag XBOX # VM86 emulation defflag VM86 +defflag PMC + # User-settable LDT (used by WINE) defflag USER_LDT Index: src/sys/arch/i386/i386/i386_trap.S diff -u src/sys/arch/i386/i386/i386_trap.S:1.6 src/sys/arch/i386/i386/i386_trap.S:1.6.6.1 --- src/sys/arch/i386/i386/i386_trap.S:1.6 Mon Feb 27 06:46:59 2017 +++ src/sys/arch/i386/i386/i386_trap.S Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: i386_trap.S,v 1.6 2017/02/27 06:46:59 chs Exp $ */ +/* $NetBSD: i386_trap.S,v 1.6.6.1 2017/08/01 23:18:30 snj Exp $ */ /* * Copyright 2002 (c) Wasabi Systems, Inc. @@ -35,7 +35,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/*- +/* * Copyright (c) 1998, 2007, 2009 The NetBSD Foundation, Inc. * All rights reserved. * @@ -66,7 +66,7 @@ #if 0 #include <machine/asm.h> -__KERNEL_RCSID(0, "$NetBSD: i386_trap.S,v 1.6 2017/02/27 06:46:59 chs Exp $"); +__KERNEL_RCSID(0, "$NetBSD: i386_trap.S,v 1.6.6.1 2017/08/01 23:18:30 snj Exp $"); #endif /* @@ -78,10 +78,10 @@ __KERNEL_RCSID(0, "$NetBSD: i386_trap.S, * (possibly the next clock tick). Thus, we disable interrupt before checking, * and only enable them again on the final `iret' or before calling the AST * handler. - */ + */ -#define TRAP(a) pushl $(a) ; jmp _C_LABEL(alltraps) -#define ZTRAP(a) pushl $0 ; TRAP(a) +#define TRAP(a) pushl $(a) ; jmp _C_LABEL(alltraps) +#define ZTRAP(a) pushl $0 ; TRAP(a) #ifdef IPKDB #define BPTTRAP(a) pushl $0; pushl $(a); jmp _C_LABEL(bpttraps) @@ -89,29 +89,49 @@ __KERNEL_RCSID(0, "$NetBSD: i386_trap.S, #define BPTTRAP(a) ZTRAP(a) #endif - .text IDTVEC(trap00) ZTRAP(T_DIVIDE) IDTVEC_END(trap00) + IDTVEC(trap01) BPTTRAP(T_TRCTRAP) IDTVEC_END(trap01) + +/* + * Non Maskable Interrupts are a special case: they can be triggered even + * with interrupts disabled, and once triggered they block further NMIs + * until an 'iret' instruction is executed. + * + * Therefore we don't enable interrupts, because the CPU could switch to + * another LWP, call 'iret' and unintentionally leave the NMI mode. + */ IDTVEC(trap02) - pushl $0 - pushl $(T_NMI) + pushl $0 + pushl $(T_NMI) INTRENTRY - jmp _C_LABEL(calltrap) + + addl $1,CPUVAR(NTRAP) /* statistical info */ + adcl $0,CPUVAR(NTRAP)+4 + pushl %esp + call _C_LABEL(trap) + addl $4,%esp + + INTRFASTEXIT IDTVEC_END(trap02) + IDTVEC(trap03) BPTTRAP(T_BPTFLT) IDTVEC_END(trap03) + IDTVEC(trap04) ZTRAP(T_OFLOW) IDTVEC_END(trap04) + IDTVEC(trap05) ZTRAP(T_BOUND) IDTVEC_END(trap05) + /* * Privileged instruction fault. */ @@ -124,21 +144,21 @@ IDTVEC(trap06) /* Check if this is a user fault. */ /* XXX this was 0x0020 in FreeBSD */ - cmpl $GSEL(GCODE_SEL, SEL_KPL), 4(%esp) /* Check code segment. */ + cmpl $GSEL(GCODE_SEL, SEL_KPL),4(%esp) /* Check code segment. */ /* If so, just handle it as a normal trap. */ jne norm_ill - + /* * This is a kernel instruction fault that might have been caused * by a DTrace provider. */ - + /* * Set our jump address for the jump back in the event that * the exception wasn't caused by DTrace at all. */ - movl $norm_ill, dtrace_invop_calltrap_addr + movl $norm_ill,dtrace_invop_calltrap_addr /* Jump to the code hooked in by DTrace. */ jmpl *dtrace_invop_jump_addr @@ -154,8 +174,9 @@ IDTVEC(trap06) ZTRAP(T_PRIVINFLT) IDTVEC_END(trap06) #endif + IDTVEC(trap07) - pushl $0 # dummy error code + pushl $0 /* dummy error code */ pushl $T_DNA INTRENTRY #ifdef DIAGNOSTIC @@ -166,24 +187,31 @@ IDTVEC(trap07) addl $4,%esp jmp _C_LABEL(trapreturn) IDTVEC_END(trap07) + IDTVEC(trap08) TRAP(T_DOUBLEFLT) IDTVEC_END(trap08) + IDTVEC(trap09) ZTRAP(T_FPOPFLT) IDTVEC_END(trap09) + IDTVEC(trap0a) TRAP(T_TSSFLT) IDTVEC_END(trap0a) + IDTVEC(trap0b) TRAP(T_SEGNPFLT) IDTVEC_END(trap0b) + IDTVEC(trap0c) TRAP(T_STKFLT) IDTVEC_END(trap0c) + IDTVEC(trap0d) TRAP(T_PROTFLT) IDTVEC_END(trap0d) + IDTVEC(trap0e) #ifndef XEN pushl $T_PAGEFLT @@ -197,9 +225,9 @@ IDTVEC(trap0e) jne calltrap movb $T_PRIVINFLT,TF_TRAPNO(%esp) jmp calltrap -#else /* !XEN */ +#else TRAP(T_PAGEFLT) -#endif /* !XEN */ +#endif IDTVEC_END(trap0e) IDTVEC(intrspurious) @@ -208,11 +236,11 @@ IDTVEC(trap0f) * The Pentium Pro local APIC may erroneously call this vector for a * default IR7. Just ignore it. * - * (The local APIC does this when CPL is raised while it's on the - * way to delivering an interrupt.. presumably enough has been set + * (The local APIC does this when CPL is raised while it's on the + * way to delivering an interrupt.. presumably enough has been set * up that it's inconvenient to abort delivery completely..) */ - pushl $0 # dummy error code + pushl $0 /* dummy error code */ pushl $T_ASTFLT INTRENTRY STI(%eax) @@ -229,18 +257,19 @@ IDTVEC(trap10) * error. It would be better to handle npx interrupts as traps but * this is difficult for nested interrupts. */ - pushl $0 # dummy error code + pushl $0 /* dummy error code */ pushl $T_ARITHTRAP .Ldo_fputrap: INTRENTRY movl CPUVAR(ILEVEL),%ebx pushl %esp - addl $1,CPUVAR(NTRAP) # statistical info + addl $1,CPUVAR(NTRAP) /* statistical info */ adcl $0,CPUVAR(NTRAP)+4 call _C_LABEL(fputrap) addl $4,%esp jmp _C_LABEL(trapreturn) IDTVEC_END(trap10) + IDTVEC(trap11) TRAP(T_ALIGNFLT) IDTVEC_END(trap11) @@ -248,8 +277,9 @@ IDTVEC_END(trap11) IDTVEC(trap12) ZTRAP(T_MCA) IDTVEC_END(trap12) + IDTVEC(trap13) - pushl $0 # dummy error code + pushl $0 /* dummy error code */ pushl $T_XMM jmp .Ldo_fputrap IDTVEC_END(trap13) @@ -308,7 +338,7 @@ IDTVEC(exceptions) .long _C_LABEL(Xtrap1e), _C_LABEL(Xtrap1f) IDTVEC_END(exceptions) - + IDTVEC(tss_trap08) 1: str %ax @@ -331,7 +361,7 @@ IDTVEC_END(tss_trap08) * Typically the code will have raised a SIGSEGV which will be actioned * by the code below. */ - .type _C_LABEL(trap_return_fault_return), @function + .type _C_LABEL(trap_return_fault_return),@function LABEL(trap_return_fault_return) mov 4(%esp),%esp /* frame for user return */ jmp _C_LABEL(trapreturn) @@ -344,8 +374,8 @@ NENTRY(alltraps) calltrap: #ifdef DIAGNOSTIC movl CPUVAR(ILEVEL),%ebx -#endif /* DIAGNOSTIC */ - addl $1,CPUVAR(NTRAP) # statistical info +#endif + addl $1,CPUVAR(NTRAP) /* statistical info */ adcl $0,CPUVAR(NTRAP)+4 pushl %esp call _C_LABEL(trap) @@ -367,7 +397,7 @@ _C_LABEL(trapreturn): .globl trapreturn 5: CLEAR_ASTPENDING(%eax) STI(%eax) movl $T_ASTFLT,TF_TRAPNO(%esp) - addl $1,CPUVAR(NTRAP) # statistical info + addl $1,CPUVAR(NTRAP) /* statistical info */ adcl $0,CPUVAR(NTRAP)+4 pushl %esp call _C_LABEL(trap) @@ -377,25 +407,25 @@ _C_LABEL(trapreturn): .globl trapreturn jnz 9f #ifdef XEN STIC(%eax) - jz 6f - call _C_LABEL(stipending) - testl %eax,%eax - jz 6f + jz 6f + call _C_LABEL(stipending) + testl %eax,%eax + jz 6f /* process pending interrupts */ CLI(%eax) - movl CPUVAR(ILEVEL), %ebx - movl $.Lalltraps_resume, %esi # address to resume loop at + movl CPUVAR(ILEVEL),%ebx + movl $.Lalltraps_resume,%esi /* address to resume loop at */ .Lalltraps_resume: - movl %ebx,%eax # get cpl - movl CPUVAR(IUNMASK)(,%eax,4),%eax - andl CPUVAR(IPENDING),%eax # any non-masked bits left? + movl %ebx,%eax /* get cpl */ + movl CPUVAR(IUNMASK)(,%eax,4),%eax + andl CPUVAR(IPENDING),%eax /* any non-masked bits left? */ jz 7f - bsrl %eax,%eax - btrl %eax,CPUVAR(IPENDING) - movl CPUVAR(ISOURCES)(,%eax,4),%eax - jmp *IS_RESUME(%eax) -7: movl %ebx, CPUVAR(ILEVEL) #restore cpl - jmp _C_LABEL(trapreturn) + bsrl %eax,%eax + btrl %eax,CPUVAR(IPENDING) + movl CPUVAR(ISOURCES)(,%eax,4),%eax + jmp *IS_RESUME(%eax) +7: movl %ebx,CPUVAR(ILEVEL) /* restore cpl */ + jmp _C_LABEL(trapreturn) #endif /* XEN */ #ifndef DIAGNOSTIC 6: INTRFASTEXIT Index: src/sys/arch/i386/include/frameasm.h diff -u src/sys/arch/i386/include/frameasm.h:1.15 src/sys/arch/i386/include/frameasm.h:1.15.46.1 --- src/sys/arch/i386/include/frameasm.h:1.15 Tue Jul 26 12:57:35 2011 +++ src/sys/arch/i386/include/frameasm.h Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: frameasm.h,v 1.15 2011/07/26 12:57:35 yamt Exp $ */ +/* $NetBSD: frameasm.h,v 1.15.46.1 2017/08/01 23:18:30 snj Exp $ */ #ifndef _I386_FRAMEASM_H_ #define _I386_FRAMEASM_H_ @@ -9,22 +9,22 @@ #endif #if !defined(XEN) -#define CLI(reg) cli -#define STI(reg) sti +#define CLI(reg) cli +#define STI(reg) sti #else /* XXX assym.h */ -#define TRAP_INSTR int $0x82 -#define XEN_BLOCK_EVENTS(reg) movb $1,EVTCHN_UPCALL_MASK(reg) -#define XEN_UNBLOCK_EVENTS(reg) movb $0,EVTCHN_UPCALL_MASK(reg) -#define XEN_TEST_PENDING(reg) testb $0xFF,EVTCHN_UPCALL_PENDING(reg) - -#define CLI(reg) movl CPUVAR(VCPU),reg ; \ - XEN_BLOCK_EVENTS(reg) -#define STI(reg) movl CPUVAR(VCPU),reg ; \ +#define TRAP_INSTR int $0x82 +#define XEN_BLOCK_EVENTS(reg) movb $1,EVTCHN_UPCALL_MASK(reg) +#define XEN_UNBLOCK_EVENTS(reg) movb $0,EVTCHN_UPCALL_MASK(reg) +#define XEN_TEST_PENDING(reg) testb $0xFF,EVTCHN_UPCALL_PENDING(reg) + +#define CLI(reg) movl CPUVAR(VCPU),reg ; \ + XEN_BLOCK_EVENTS(reg) +#define STI(reg) movl CPUVAR(VCPU),reg ; \ XEN_UNBLOCK_EVENTS(reg) -#define STIC(reg) movl CPUVAR(VCPU),reg ; \ +#define STIC(reg) movl CPUVAR(VCPU),reg ; \ XEN_UNBLOCK_EVENTS(reg) ; \ - testb $0xff,EVTCHN_UPCALL_PENDING(reg) + testb $0xff,EVTCHN_UPCALL_PENDING(reg) #endif #ifndef TRAPLOG @@ -60,7 +60,7 @@ rdmsr ; \ movl %eax,TREC_IBT(%ebx) #endif - + /* * These are used on interrupt or trap entry or exit. */ Index: src/sys/arch/x86/include/sysarch.h diff -u src/sys/arch/x86/include/sysarch.h:1.11 src/sys/arch/x86/include/sysarch.h:1.11.6.1 --- src/sys/arch/x86/include/sysarch.h:1.11 Fri Mar 10 13:09:11 2017 +++ src/sys/arch/x86/include/sysarch.h Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sysarch.h,v 1.11 2017/03/10 13:09:11 maxv Exp $ */ +/* $NetBSD: sysarch.h,v 1.11.6.1 2017/08/01 23:18:30 snj Exp $ */ /*- * Copyright (c) 2007 The NetBSD Foundation, Inc. @@ -134,6 +134,7 @@ struct _X86_SYSARCH_L(pmc_info_args) { int vers; int type; uint32_t nctrs; + uint64_t nsamp; }; #define PMC_VERSION 1 Index: src/sys/arch/x86/x86/pmc.c diff -u src/sys/arch/x86/x86/pmc.c:1.7 src/sys/arch/x86/x86/pmc.c:1.7.2.1 --- src/sys/arch/x86/x86/pmc.c:1.7 Tue May 23 08:54:39 2017 +++ src/sys/arch/x86/x86/pmc.c Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: pmc.c,v 1.7 2017/05/23 08:54:39 nonaka Exp $ */ +/* $NetBSD: pmc.c,v 1.7.2.1 2017/08/01 23:18:30 snj Exp $ */ /* * Copyright (c) 2017 The NetBSD Foundation, Inc. @@ -63,24 +63,32 @@ */ /* - * Interface to x86 CPU Performance Counters. + * Interface to x86 CPU Performance Counters. System-wide only, for now. + * + * For each PMC on each CPU, two pieces of information are returned to userland: + * the number of overflows, and the current value of the PMC. It means that the + * total number of events for the given PMC on the given CPU is computable the + * following way: + * tot_n_events = NEVENTS_SAMPLE * overfl + ctrval */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pmc.c,v 1.7 2017/05/23 08:54:39 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmc.c,v 1.7.2.1 2017/08/01 23:18:30 snj Exp $"); + +#include "opt_pmc.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/proc.h> #include <sys/cpu.h> #include <sys/xcall.h> +#include <sys/kauth.h> #include <machine/cpufunc.h> #include <machine/cpuvar.h> #include <machine/specialreg.h> #include <machine/sysarch.h> #include <machine/pmc.h> -#include <machine/cpu_counter.h> #include <machine/cputypes.h> #include <machine/i82489reg.h> #include <machine/i82489var.h> @@ -89,8 +97,12 @@ __KERNEL_RCSID(0, "$NetBSD: pmc.c,v 1.7 #define NEVENTS_SAMPLE 500000 +/* + * Structure describing a PMC. + */ typedef struct { bool running; + size_t n; /* pmc number */ uint32_t evtmsr; /* event selector MSR */ uint64_t evtval; /* event selector value */ uint32_t ctrmsr; /* counter MSR */ @@ -99,21 +111,36 @@ typedef struct { uint64_t ctrmask; } pmc_state_t; -static nmi_handler_t *pmc_nmi_handle; -static uint32_t pmc_lapic_image[MAXCPUS]; +/* + * Per-CPU structure that describes the values of each PMC, plus the state + * of the LAPIC before enabling PMCs. + */ +typedef struct { + x86_pmc_cpuval_t val[PMC_NCOUNTERS]; /* values returned to user */ + uint64_t nmioverfl[PMC_NCOUNTERS]; /* incremented by NMI intr */ + uint32_t lapic_image; /* saved content of LAPIC */ +} pmc_cpu_t; + +static pmc_state_t pmc_state[PMC_NCOUNTERS]; +static pmc_cpu_t pmc_cpu[MAXCPUS]; -static x86_pmc_cpuval_t pmc_val_cpus[MAXCPUS] __aligned(CACHE_LINE_SIZE); +static nmi_handler_t *pmc_nmi_handle; static kmutex_t pmc_lock; -static pmc_state_t pmc_state[PMC_NCOUNTERS]; static uint32_t pmc_ncounters __read_mostly; static int pmc_type __read_mostly; +/* + * Handle PMC overflows. Called from NMI interrupt context, with interrupts + * disabled. + */ static int pmc_nmi(const struct trapframe *tf, void *dummy) { struct cpu_info *ci = curcpu(); pmc_state_t *pmc; + pmc_cpu_t *cpu; + uint64_t ctr; size_t i; if (pmc_type == PMC_TYPE_NONE) { @@ -124,7 +151,11 @@ pmc_nmi(const struct trapframe *tf, void if (!pmc->running) { continue; } - /* XXX make sure it really comes from this PMC */ + ctr = rdmsr(pmc->ctrmsr); + /* If the highest bit is zero, then it's this PMC */ + if ((ctr & ((pmc->ctrmask + 1) >> 1)) != 0) { + continue; + } break; } if (i == pmc_ncounters) { @@ -132,7 +163,8 @@ pmc_nmi(const struct trapframe *tf, void } /* Count the overflow, and restart the counter */ - pmc_val_cpus[cpu_index(ci)].overfl++; + cpu = &pmc_cpu[cpu_index(ci)]; + cpu->nmioverfl[i]++; wrmsr(pmc->ctrmsr, pmc->ctrinitval); return 1; @@ -143,9 +175,37 @@ pmc_read_cpu(void *arg1, void *arg2) { pmc_state_t *pmc = (pmc_state_t *)arg1; struct cpu_info *ci = curcpu(); + pmc_cpu_t *cpu = &pmc_cpu[cpu_index(ci)]; + uint64_t evtmsr, en; + + switch (pmc_type) { + case PMC_TYPE_I686: + en = PMC6_EVTSEL_EN; + break; + + case PMC_TYPE_K7: + en = K7_EVTSEL_EN; + break; + + case PMC_TYPE_F10H: + en = F10H_EVTSEL_EN; + break; + } + + evtmsr = rdmsr(pmc->evtmsr); + + /* + * Quickly disable the counter, to avoid getting an NMI after setting + * ctrval. + */ + wrmsr(pmc->evtmsr, evtmsr & ~en); - pmc_val_cpus[cpu_index(ci)].ctrval = + cpu->val[pmc->n].ctrval = (rdmsr(pmc->ctrmsr) & pmc->ctrmask) - pmc->ctrinitval; + cpu->val[pmc->n].overfl = cpu->nmioverfl[pmc->n]; + + /* Re-enable the counter */ + wrmsr(pmc->evtmsr, evtmsr); } static void @@ -154,9 +214,14 @@ pmc_apply_cpu(void *arg1, void *arg2) pmc_state_t *pmc = (pmc_state_t *)arg1; bool start = (bool)arg2; struct cpu_info *ci = curcpu(); + pmc_cpu_t *cpu = &pmc_cpu[cpu_index(ci)]; if (start) { - pmc_lapic_image[cpu_index(ci)] = lapic_readreg(LAPIC_PCINT); + cpu->lapic_image = lapic_readreg(LAPIC_PCINT); + cpu->val[pmc->n].ctrval = 0; + cpu->val[pmc->n].overfl = 0; + cpu->nmioverfl[pmc->n] = 0; + lapic_writereg(LAPIC_PCINT, LAPIC_DLMODE_NMI); } @@ -169,11 +234,8 @@ pmc_apply_cpu(void *arg1, void *arg2) break; } - pmc_val_cpus[cpu_index(ci)].ctrval = 0; - pmc_val_cpus[cpu_index(ci)].overfl = 0; - if (!start) { - lapic_writereg(LAPIC_PCINT, pmc_lapic_image[cpu_index(ci)]); + lapic_writereg(LAPIC_PCINT, cpu->lapic_image); } } @@ -287,6 +349,7 @@ pmc_init(void) pmc_type = PMC_TYPE_I686; pmc_ncounters = 2; for (i = 0; i < pmc_ncounters; i++) { + pmc_state[i].n = i; pmc_state[i].evtmsr = MSR_EVNTSEL0 + i; pmc_state[i].ctrmsr = MSR_PERFCTR0 + i; pmc_state[i].ctrmaxval = (UINT64_C(1) << 40) - 1; @@ -297,6 +360,7 @@ pmc_init(void) pmc_type = PMC_TYPE_F10H; pmc_ncounters = 4; for (i = 0; i < pmc_ncounters; i++) { + pmc_state[i].n = i; pmc_state[i].evtmsr = MSR_F10H_EVNTSEL0 + i; pmc_state[i].ctrmsr = MSR_F10H_PERFCTR0 + i; pmc_state[i].ctrmaxval = @@ -308,6 +372,7 @@ pmc_init(void) pmc_type = PMC_TYPE_K7; pmc_ncounters = 4; for (i = 0; i < pmc_ncounters; i++) { + pmc_state[i].n = i; pmc_state[i].evtmsr = MSR_K7_EVNTSEL0 + i; pmc_state[i].ctrmsr = MSR_K7_PERFCTR0 + i; pmc_state[i].ctrmaxval = @@ -325,12 +390,19 @@ int sys_pmc_info(struct lwp *l, struct x86_pmc_info_args *uargs, register_t *retval) { struct x86_pmc_info_args rv; + int error; + + error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_X86PMC, + NULL, NULL, NULL, NULL); + if (error) + return error; memset(&rv, 0, sizeof(rv)); rv.vers = PMC_VERSION; rv.type = pmc_type; rv.nctrs = pmc_ncounters; + rv.nsamp = NEVENTS_SAMPLE; return copyout(&rv, uargs, sizeof(rv)); } @@ -344,6 +416,11 @@ sys_pmc_startstop(struct lwp *l, struct bool start; int error; + error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_X86PMC, + NULL, NULL, NULL, NULL); + if (error) + return error; + if (pmc_type == PMC_TYPE_NONE) return ENODEV; @@ -383,9 +460,15 @@ sys_pmc_read(struct lwp *l, struct x86_p { struct x86_pmc_read_args args; pmc_state_t *pmc; - size_t nval; + pmc_cpu_t *cpu; + size_t i, nval; int error; + error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_X86PMC, + NULL, NULL, NULL, NULL); + if (error) + return error; + if (pmc_type == PMC_TYPE_NONE) return ENODEV; @@ -405,8 +488,16 @@ sys_pmc_read(struct lwp *l, struct x86_p if (pmc->running) { pmc_read(pmc); - error = copyout(&pmc_val_cpus, args.values, - nval * sizeof(x86_pmc_cpuval_t)); + + for (i = 0; i < nval; i++) { + cpu = &pmc_cpu[i]; + + error = copyout(&cpu->val[pmc->n], args.values + i, + sizeof(x86_pmc_cpuval_t)); + if (error) + break; + } + args.nval = nval; } else { error = ENOENT; Index: src/sys/arch/x86/x86/sys_machdep.c diff -u src/sys/arch/x86/x86/sys_machdep.c:1.35 src/sys/arch/x86/x86/sys_machdep.c:1.35.6.1 --- src/sys/arch/x86/x86/sys_machdep.c:1.35 Fri Mar 10 14:54:12 2017 +++ src/sys/arch/x86/x86/sys_machdep.c Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_machdep.c,v 1.35 2017/03/10 14:54:12 maxv Exp $ */ +/* $NetBSD: sys_machdep.c,v 1.35.6.1 2017/08/01 23:18:30 snj Exp $ */ /*- * Copyright (c) 1998, 2007, 2009 The NetBSD Foundation, Inc. @@ -30,9 +30,10 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.35 2017/03/10 14:54:12 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.35.6.1 2017/08/01 23:18:30 snj Exp $"); #include "opt_mtrr.h" +#include "opt_pmc.h" #include "opt_user_ldt.h" #include "opt_compat_netbsd.h" #ifdef i386 Index: src/sys/arch/xen/conf/files.compat diff -u src/sys/arch/xen/conf/files.compat:1.25 src/sys/arch/xen/conf/files.compat:1.25.8.1 --- src/sys/arch/xen/conf/files.compat:1.25 Tue Dec 13 10:54:27 2016 +++ src/sys/arch/xen/conf/files.compat Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -# $NetBSD: files.compat,v 1.25 2016/12/13 10:54:27 kamil Exp $ +# $NetBSD: files.compat,v 1.25.8.1 2017/08/01 23:18:30 snj Exp $ # NetBSD: files.x86,v 1.10 2003/10/08 17:30:00 bouyer Exp # options for MP configuration through the MP spec @@ -28,6 +28,8 @@ defflag opt_pcifixup.h XXXOPT_PCIFIXUP # VM86 emulation defflag opt_vm86.h XXXVM86 +defflag opt_pmc.h XXXPMC + # User-settable LDT (used by WINE) defflag opt_user_ldt.h XXXUSER_LDT Index: src/sys/secmodel/suser/secmodel_suser.c diff -u src/sys/secmodel/suser/secmodel_suser.c:1.42 src/sys/secmodel/suser/secmodel_suser.c:1.42.10.1 --- src/sys/secmodel/suser/secmodel_suser.c:1.42 Mon Aug 17 06:16:03 2015 +++ src/sys/secmodel/suser/secmodel_suser.c Tue Aug 1 23:18:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: secmodel_suser.c,v 1.42 2015/08/17 06:16:03 knakahara Exp $ */ +/* $NetBSD: secmodel_suser.c,v 1.42.10.1 2017/08/01 23:18:30 snj Exp $ */ /*- * Copyright (c) 2006 Elad Efrat <e...@netbsd.org> * All rights reserved. @@ -38,7 +38,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: secmodel_suser.c,v 1.42 2015/08/17 06:16:03 knakahara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: secmodel_suser.c,v 1.42.10.1 2017/08/01 23:18:30 snj Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -834,13 +834,13 @@ int secmodel_suser_machdep_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) { - bool isroot; - int result; + bool isroot; + int result; - isroot = suser_isroot(cred); - result = KAUTH_RESULT_DEFER; + isroot = suser_isroot(cred); + result = KAUTH_RESULT_DEFER; - switch (action) { + switch (action) { case KAUTH_MACHDEP_CPU_UCODE_APPLY: case KAUTH_MACHDEP_IOPERM_GET: case KAUTH_MACHDEP_LDT_GET: @@ -853,6 +853,7 @@ secmodel_suser_machdep_cb(kauth_cred_t c case KAUTH_MACHDEP_NVRAM: case KAUTH_MACHDEP_UNMANAGEDMEM: case KAUTH_MACHDEP_PXG: + case KAUTH_MACHDEP_X86PMC: if (isroot) result = KAUTH_RESULT_ALLOW; break; @@ -875,11 +876,11 @@ int secmodel_suser_device_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) { - bool isroot; - int result; + bool isroot; + int result; - isroot = suser_isroot(cred); - result = KAUTH_RESULT_DEFER; + isroot = suser_isroot(cred); + result = KAUTH_RESULT_DEFER; switch (action) { case KAUTH_DEVICE_BLUETOOTH_SETPRIV: Index: src/sys/sys/kauth.h diff -u src/sys/sys/kauth.h:1.73 src/sys/sys/kauth.h:1.73.10.1 --- src/sys/sys/kauth.h:1.73 Tue Oct 6 22:13:39 2015 +++ src/sys/sys/kauth.h Tue Aug 1 23:18:31 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: kauth.h,v 1.73 2015/10/06 22:13:39 christos Exp $ */ +/* $NetBSD: kauth.h,v 1.73.10.1 2017/08/01 23:18:31 snj Exp $ */ /*- * Copyright (c) 2005, 2006 Elad Efrat <e...@netbsd.org> @@ -321,6 +321,7 @@ enum { KAUTH_MACHDEP_NVRAM, KAUTH_MACHDEP_UNMANAGEDMEM, KAUTH_MACHDEP_PXG, + KAUTH_MACHDEP_X86PMC }; /* Index: src/usr.bin/pmc/Makefile diff -u src/usr.bin/pmc/Makefile:1.4 src/usr.bin/pmc/Makefile:1.4.4.1 --- src/usr.bin/pmc/Makefile:1.4 Wed Mar 8 16:05:29 2017 +++ src/usr.bin/pmc/Makefile Tue Aug 1 23:18:31 2017 @@ -1,6 +1,6 @@ -# $NetBSD: Makefile,v 1.4 2017/03/08 16:05:29 maxv Exp $ +# $NetBSD: Makefile,v 1.4.4.1 2017/08/01 23:18:31 snj Exp $ -.if (${MACHINE_ARCH} == "i386") +.if (${MACHINE_ARCH} == "i386") || (${MACHINE_ARCH} == "x86_64") PROG= pmc .else MAN= pmc.1 Index: src/usr.bin/pmc/pmc.1 diff -u src/usr.bin/pmc/pmc.1:1.11 src/usr.bin/pmc/pmc.1:1.11.4.1 --- src/usr.bin/pmc/pmc.1:1.11 Fri Mar 10 15:34:17 2017 +++ src/usr.bin/pmc/pmc.1 Tue Aug 1 23:18:31 2017 @@ -1,4 +1,4 @@ -.\" $NetBSD: pmc.1,v 1.11 2017/03/10 15:34:17 wiz Exp $ +.\" $NetBSD: pmc.1,v 1.11.4.1 2017/08/01 23:18:31 snj Exp $ .\" .\" Copyright (c) 2017 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -58,7 +58,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd March 10, 2017 +.Dd July 12, 2017 .Dt PMC 1 .Os .Sh NAME @@ -71,7 +71,8 @@ .Sh DESCRIPTION The .Nm -command can be used to control and inspect the state of CPUs in the system. +tool can be used to control and inspect the state of the +Performance-Monitoring Counters (PMCs) in the system. .Pp The first argument, .Ar command , @@ -95,24 +96,34 @@ specifies the source of the event; it mu Stop any performance counters that are currently running, and display the values of these counters. .El +.Sh FILES +.Pa src/sys/arch/x86/x86/pmc.c +x86 implementation. +.Pp +.Pa src/usr.bin/pmc/pmc.c +pmc tool. .Sh EXAMPLES The following command prints the available counters. -.Dl $ pmc list +.Dl # pmc list .Pp The following command starts two counters. The former will count the 'l2cache-access' events that are triggered from userland, the latter will count the 'l1cache-access' events triggered from both userland and the kernel. -.Dl $ pmc start l2cache-access:u l1cache-access:uk +.Dl # pmc start l2cache-access:u l1cache-access:uk .Pp Note that the two following commands are not exactly identical. -.Dl $ pmc start l1cache-access:u l1cache-access:k -.Dl $ pmc start l1cache-access:uk +.Dl # pmc start l1cache-access:u l1cache-access:k +.Dl # pmc start l1cache-access:uk The former will start two different counters that have a different source but track the same event. The latter will start one counter that tracks the event from all sources; it therefore does the sum of the two counters from the first command, but takes only one counter to do so. +.Sh INTERPRETING RESULTS +For each PMC on each CPU, the value reported by the +.Nm +tool is the number of events counted, encoded in a 64bit integer. .Sh DIAGNOSTICS .Bl -diag .It PMC support not compiled into the kernel @@ -132,9 +143,10 @@ The .Nm command first appeared in .Nx 1.6 . -It was revamped in 2017. +It was revamped in +.Nx 8.0 . .Sh BUGS The .Nm command currently only supports performance-monitoring counters -on the i386 architecture. +on the i386 and amd64 architectures. Index: src/usr.bin/pmc/pmc.c diff -u src/usr.bin/pmc/pmc.c:1.23 src/usr.bin/pmc/pmc.c:1.23.4.1 --- src/usr.bin/pmc/pmc.c:1.23 Fri Mar 24 18:30:44 2017 +++ src/usr.bin/pmc/pmc.c Tue Aug 1 23:18:31 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: pmc.c,v 1.23 2017/03/24 18:30:44 maxv Exp $ */ +/* $NetBSD: pmc.c,v 1.23.4.1 2017/08/01 23:18:31 snj Exp $ */ /* * Copyright (c) 2017 The NetBSD Foundation, Inc. @@ -66,7 +66,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: pmc.c,v 1.23 2017/03/24 18:30:44 maxv Exp $"); +__RCSID("$NetBSD: pmc.c,v 1.23.4.1 2017/08/01 23:18:31 snj Exp $"); #endif #include <inttypes.h> @@ -379,6 +379,7 @@ static int x86_pmc_startstop(x86_pmc_sta static int x86_pmc_read(x86_pmc_read_args_t *); static uint32_t pmc_ncounters; +static size_t pmc_nsamples; static struct cmdtab { const char *label; @@ -428,6 +429,7 @@ pmc_start(const pmc_name2val_cpu_t *pncp uint32_t flags; size_t n, i; + /* Get the source for each counter (kernel or userland) */ for (n = 0; n < pmc_ncounters; n++) { if (argv[n] == NULL) break; @@ -437,6 +439,7 @@ pmc_start(const pmc_name2val_cpu_t *pncp usage(); } + /* Initialize each pmcarg structure */ for (i = 0; i < n; i++) { pmcarg = &pmcargs[i]; event = tokens[i][0]; @@ -460,6 +463,7 @@ pmc_start(const pmc_name2val_cpu_t *pncp pmcarg->flags = flags; } + /* Finally, start each counter */ for (i = 0; i < n; i++) { pmcarg = &pmcargs[i]; if (x86_pmc_startstop(pmcarg) < 0) @@ -475,6 +479,7 @@ pmc_stop(const pmc_name2val_cpu_t *pncp, x86_pmc_startstop_args_t pmcstop; x86_pmc_read_args_t pmcread; size_t i, j, n, nval = 0; + uint64_t val; /* Read the values. */ for (n = 0; n < pmc_ncounters; n++) { @@ -510,7 +515,9 @@ pmc_stop(const pmc_name2val_cpu_t *pncp, for (i = 0; i < n; i++) { printf("%zu\t\t", i); for (j = 0; j < nval; j++) { - printf("%" PRIu64 "\t\t", cpuval[i][j].ctrval); + val = cpuval[i][j].overfl * pmc_nsamples + + cpuval[i][j].ctrval; + printf("%" PRIu64 "\t\t", val); } printf("\n"); } @@ -585,11 +592,21 @@ main(int argc, char **argv) setprogname(argv[0]); argv += 1; - if (x86_pmc_info(&pmcinfo) < 0) - errx(EXIT_FAILURE, "PMC support not compiled into the kernel"); + if (argc < 2) + usage(); + + if (x86_pmc_info(&pmcinfo) < 0) { + if (errno == EPERM) + errx(EXIT_FAILURE, + "PMC operations require root privileges"); + else + errx(EXIT_FAILURE, + "PMC support not compiled into the kernel"); + } if (pmcinfo.vers != 1) errx(EXIT_FAILURE, "Wrong PMC version"); pmc_ncounters = pmcinfo.nctrs; + pmc_nsamples = pmcinfo.nsamp; pncp = pmc_lookup_cpu(pmcinfo.type); if (pncp == NULL)