1 1.8 msaitoh /* $NetBSD: tprof_x86_intel.c,v 1.8 2023/04/11 10:07:12 msaitoh Exp $ */ 2 1.1 maxv 3 1.1 maxv /* 4 1.1 maxv * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 1.1 maxv * All rights reserved. 6 1.1 maxv * 7 1.1 maxv * This code is derived from software contributed to The NetBSD Foundation 8 1.1 maxv * by Maxime Villard. 9 1.1 maxv * 10 1.1 maxv * Redistribution and use in source and binary forms, with or without 11 1.1 maxv * modification, are permitted provided that the following conditions 12 1.1 maxv * are met: 13 1.1 maxv * 1. Redistributions of source code must retain the above copyright 14 1.1 maxv * notice, this list of conditions and the following disclaimer. 15 1.1 maxv * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 maxv * notice, this list of conditions and the following disclaimer in the 17 1.1 maxv * documentation and/or other materials provided with the distribution. 18 1.1 maxv * 19 1.1 maxv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 maxv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 maxv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 maxv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 maxv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 maxv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 maxv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 maxv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 maxv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 maxv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 maxv * POSSIBILITY OF SUCH DAMAGE. 30 1.1 maxv */ 31 1.1 maxv 32 1.1 maxv /* 33 1.1 maxv * Copyright (c)2008,2009 YAMAMOTO Takashi, 34 1.1 maxv * All rights reserved. 35 1.1 maxv * 36 1.1 maxv * Redistribution and use in source and binary forms, with or without 37 1.1 maxv * modification, are permitted provided that the following conditions 38 1.1 maxv * are met: 39 1.1 maxv * 1. Redistributions of source code must retain the above copyright 40 1.1 maxv * notice, this list of conditions and the following disclaimer. 41 1.1 maxv * 2. Redistributions in binary form must reproduce the above copyright 42 1.1 maxv * notice, this list of conditions and the following disclaimer in the 43 1.1 maxv * documentation and/or other materials provided with the distribution. 44 1.1 maxv * 45 1.1 maxv * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 1.1 maxv * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 1.1 maxv * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 1.1 maxv * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49 1.1 maxv * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 1.1 maxv * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 1.1 maxv * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 1.1 maxv * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 1.1 maxv * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 1.1 maxv * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 1.1 maxv * SUCH DAMAGE. 56 1.1 maxv */ 57 1.1 maxv 58 1.1 maxv #include <sys/cdefs.h> 59 1.8 msaitoh __KERNEL_RCSID(0, "$NetBSD: tprof_x86_intel.c,v 1.8 2023/04/11 10:07:12 msaitoh Exp $"); 60 1.1 maxv 61 1.1 maxv #include <sys/param.h> 62 1.1 maxv #include <sys/systm.h> 63 1.1 maxv #include <sys/kernel.h> 64 1.1 maxv #include <sys/module.h> 65 1.1 maxv 66 1.1 maxv #include <sys/cpu.h> 67 1.5 ryo #include <sys/percpu.h> 68 1.1 maxv #include <sys/xcall.h> 69 1.1 maxv 70 1.1 maxv #include <dev/tprof/tprof.h> 71 1.1 maxv 72 1.1 maxv #include <uvm/uvm.h> /* VM_MIN_KERNEL_ADDRESS */ 73 1.1 maxv 74 1.1 maxv #include <x86/nmi.h> 75 1.1 maxv 76 1.1 maxv #include <machine/cpufunc.h> 77 1.1 maxv #include <machine/cputypes.h> /* CPUVENDOR_* */ 78 1.1 maxv #include <machine/cpuvar.h> /* cpu_vendor */ 79 1.1 maxv #include <machine/i82489reg.h> 80 1.1 maxv #include <machine/i82489var.h> 81 1.1 maxv 82 1.5 ryo static u_int counter_bitwidth; 83 1.5 ryo 84 1.5 ryo #define PERFEVTSEL(i) (MSR_EVNTSEL0 + (i)) 85 1.5 ryo #define PERFCTR(i) (MSR_PERFCTR0 + (i)) 86 1.5 ryo 87 1.1 maxv #define PERFEVTSEL_EVENT_SELECT __BITS(0, 7) 88 1.1 maxv #define PERFEVTSEL_UNIT_MASK __BITS(8, 15) 89 1.1 maxv #define PERFEVTSEL_USR __BIT(16) 90 1.1 maxv #define PERFEVTSEL_OS __BIT(17) 91 1.1 maxv #define PERFEVTSEL_E __BIT(18) 92 1.1 maxv #define PERFEVTSEL_PC __BIT(19) 93 1.1 maxv #define PERFEVTSEL_INT __BIT(20) 94 1.1 maxv #define PERFEVTSEL_EN __BIT(22) 95 1.1 maxv #define PERFEVTSEL_INV __BIT(23) 96 1.1 maxv #define PERFEVTSEL_COUNTER_MASK __BITS(24, 31) 97 1.1 maxv 98 1.1 maxv static uint32_t intel_lapic_saved[MAXCPUS]; 99 1.1 maxv static nmi_handler_t *intel_nmi_handle; 100 1.5 ryo 101 1.5 ryo static uint32_t 102 1.5 ryo tprof_intel_ncounters(void) 103 1.5 ryo { 104 1.6 msaitoh uint32_t descs[4]; 105 1.6 msaitoh 106 1.7 msaitoh if (cpuid_level < 0x0a) 107 1.7 msaitoh return 0; 108 1.7 msaitoh 109 1.6 msaitoh x86_cpuid(0x0a, descs); 110 1.6 msaitoh 111 1.6 msaitoh return __SHIFTOUT(descs[0], CPUID_PERF_NGPPC); 112 1.5 ryo } 113 1.5 ryo 114 1.5 ryo static u_int 115 1.5 ryo tprof_intel_counter_bitwidth(u_int counter) 116 1.5 ryo { 117 1.8 msaitoh 118 1.5 ryo return counter_bitwidth; 119 1.5 ryo } 120 1.5 ryo 121 1.5 ryo static inline void 122 1.5 ryo tprof_intel_counter_write(u_int counter, uint64_t val) 123 1.5 ryo { 124 1.8 msaitoh 125 1.5 ryo wrmsr(PERFCTR(counter), val); 126 1.5 ryo } 127 1.5 ryo 128 1.5 ryo static inline uint64_t 129 1.5 ryo tprof_intel_counter_read(u_int counter) 130 1.5 ryo { 131 1.8 msaitoh 132 1.5 ryo return rdmsr(PERFCTR(counter)); 133 1.5 ryo } 134 1.1 maxv 135 1.1 maxv static void 136 1.5 ryo tprof_intel_configure_event(u_int counter, const tprof_param_t *param) 137 1.1 maxv { 138 1.1 maxv uint64_t evtval; 139 1.1 maxv 140 1.1 maxv evtval = 141 1.5 ryo __SHIFTIN(param->p_event, PERFEVTSEL_EVENT_SELECT) | 142 1.5 ryo __SHIFTIN(param->p_unit, PERFEVTSEL_UNIT_MASK) | 143 1.5 ryo ((param->p_flags & TPROF_PARAM_USER) ? PERFEVTSEL_USR : 0) | 144 1.5 ryo ((param->p_flags & TPROF_PARAM_KERN) ? PERFEVTSEL_OS : 0) | 145 1.5 ryo PERFEVTSEL_INT; 146 1.5 ryo wrmsr(PERFEVTSEL(counter), evtval); 147 1.1 maxv 148 1.8 msaitoh /* Reset the counter */ 149 1.5 ryo tprof_intel_counter_write(counter, param->p_value); 150 1.5 ryo } 151 1.1 maxv 152 1.5 ryo static void 153 1.5 ryo tprof_intel_start(tprof_countermask_t runmask) 154 1.5 ryo { 155 1.5 ryo int bit; 156 1.5 ryo 157 1.5 ryo while ((bit = ffs(runmask)) != 0) { 158 1.5 ryo bit--; 159 1.5 ryo CLR(runmask, __BIT(bit)); 160 1.5 ryo wrmsr(PERFEVTSEL(bit), rdmsr(PERFEVTSEL(bit)) | PERFEVTSEL_EN); 161 1.5 ryo } 162 1.1 maxv } 163 1.1 maxv 164 1.1 maxv static void 165 1.5 ryo tprof_intel_stop(tprof_countermask_t stopmask) 166 1.1 maxv { 167 1.5 ryo int bit; 168 1.1 maxv 169 1.5 ryo while ((bit = ffs(stopmask)) != 0) { 170 1.5 ryo bit--; 171 1.5 ryo CLR(stopmask, __BIT(bit)); 172 1.8 msaitoh wrmsr(PERFEVTSEL(bit), rdmsr(PERFEVTSEL(bit)) & 173 1.8 msaitoh ~PERFEVTSEL_EN); 174 1.5 ryo } 175 1.1 maxv } 176 1.1 maxv 177 1.1 maxv static int 178 1.5 ryo tprof_intel_nmi(const struct trapframe *tf, void *arg) 179 1.1 maxv { 180 1.5 ryo tprof_backend_softc_t *sc = arg; 181 1.5 ryo tprof_frame_info_t tfi; 182 1.1 maxv uint32_t pcint; 183 1.5 ryo int bit; 184 1.1 maxv 185 1.5 ryo uint64_t *counters_offset = 186 1.5 ryo percpu_getptr_remote(sc->sc_ctr_offset_percpu, curcpu()); 187 1.5 ryo tprof_countermask_t mask = sc->sc_ctr_ovf_mask; 188 1.5 ryo while ((bit = ffs(mask)) != 0) { 189 1.5 ryo bit--; 190 1.5 ryo CLR(mask, __BIT(bit)); 191 1.5 ryo 192 1.5 ryo /* If the highest bit is non zero, then it's not for us. */ 193 1.5 ryo uint64_t ctr = tprof_intel_counter_read(bit); 194 1.5 ryo if ((ctr & __BIT(counter_bitwidth - 1)) != 0) 195 1.5 ryo continue; /* not overflowed */ 196 1.5 ryo 197 1.5 ryo if (ISSET(sc->sc_ctr_prof_mask, __BIT(bit))) { 198 1.8 msaitoh /* Account for the counter, and reset */ 199 1.5 ryo tprof_intel_counter_write(bit, 200 1.5 ryo sc->sc_count[bit].ctr_counter_reset_val); 201 1.5 ryo counters_offset[bit] += 202 1.5 ryo sc->sc_count[bit].ctr_counter_val + ctr; 203 1.1 maxv 204 1.8 msaitoh /* Record a sample */ 205 1.1 maxv #if defined(__x86_64__) 206 1.5 ryo tfi.tfi_pc = tf->tf_rip; 207 1.1 maxv #else 208 1.5 ryo tfi.tfi_pc = tf->tf_eip; 209 1.1 maxv #endif 210 1.5 ryo tfi.tfi_counter = bit; 211 1.5 ryo tfi.tfi_inkernel = tfi.tfi_pc >= VM_MIN_KERNEL_ADDRESS; 212 1.5 ryo tprof_sample(NULL, &tfi); 213 1.5 ryo } else { 214 1.8 msaitoh /* Not profiled, but require to consider overflow */ 215 1.5 ryo counters_offset[bit] += __BIT(counter_bitwidth); 216 1.5 ryo } 217 1.5 ryo } 218 1.1 maxv 219 1.8 msaitoh /* Unmask PMI */ 220 1.3 msaitoh pcint = lapic_readreg(LAPIC_LVT_PCINT); 221 1.1 maxv KASSERT((pcint & LAPIC_LVT_MASKED) != 0); 222 1.3 msaitoh lapic_writereg(LAPIC_LVT_PCINT, pcint & ~LAPIC_LVT_MASKED); 223 1.1 maxv 224 1.1 maxv return 1; 225 1.1 maxv } 226 1.1 maxv 227 1.1 maxv static uint64_t 228 1.5 ryo tprof_intel_counter_estimate_freq(u_int counter) 229 1.1 maxv { 230 1.8 msaitoh 231 1.5 ryo return curcpu()->ci_data.cpu_cc_freq; 232 1.1 maxv } 233 1.1 maxv 234 1.1 maxv static uint32_t 235 1.1 maxv tprof_intel_ident(void) 236 1.1 maxv { 237 1.1 maxv uint32_t descs[4]; 238 1.1 maxv 239 1.8 msaitoh if (cpu_vendor != CPUVENDOR_INTEL) 240 1.1 maxv return TPROF_IDENT_NONE; 241 1.1 maxv 242 1.8 msaitoh if (cpuid_level < 0x0a) 243 1.1 maxv return TPROF_IDENT_NONE; 244 1.8 msaitoh 245 1.8 msaitoh x86_cpuid(0x0a, descs); 246 1.8 msaitoh if ((descs[0] & CPUID_PERF_VERSION) == 0) 247 1.1 maxv return TPROF_IDENT_NONE; 248 1.8 msaitoh 249 1.8 msaitoh if ((descs[0] & CPUID_PERF_NGPPC) == 0) 250 1.1 maxv return TPROF_IDENT_NONE; 251 1.1 maxv 252 1.4 msaitoh counter_bitwidth = __SHIFTOUT(descs[0], CPUID_PERF_NBWGPPC); 253 1.1 maxv 254 1.1 maxv return TPROF_IDENT_INTEL_GENERIC; 255 1.1 maxv } 256 1.1 maxv 257 1.5 ryo static void 258 1.5 ryo tprof_intel_establish_cpu(void *arg1, void *arg2) 259 1.5 ryo { 260 1.5 ryo struct cpu_info * const ci = curcpu(); 261 1.5 ryo 262 1.5 ryo intel_lapic_saved[cpu_index(ci)] = lapic_readreg(LAPIC_LVT_PCINT); 263 1.5 ryo lapic_writereg(LAPIC_LVT_PCINT, LAPIC_DLMODE_NMI); 264 1.5 ryo } 265 1.5 ryo 266 1.5 ryo static void 267 1.5 ryo tprof_intel_disestablish_cpu(void *arg1, void *arg2) 268 1.5 ryo { 269 1.5 ryo struct cpu_info * const ci = curcpu(); 270 1.5 ryo 271 1.5 ryo lapic_writereg(LAPIC_LVT_PCINT, intel_lapic_saved[cpu_index(ci)]); 272 1.5 ryo } 273 1.5 ryo 274 1.1 maxv static int 275 1.5 ryo tprof_intel_establish(tprof_backend_softc_t *sc) 276 1.1 maxv { 277 1.1 maxv uint64_t xc; 278 1.1 maxv 279 1.8 msaitoh if (tprof_intel_ident() == TPROF_IDENT_NONE) 280 1.1 maxv return ENOTSUP; 281 1.1 maxv 282 1.1 maxv KASSERT(intel_nmi_handle == NULL); 283 1.5 ryo intel_nmi_handle = nmi_establish(tprof_intel_nmi, sc); 284 1.1 maxv 285 1.5 ryo xc = xc_broadcast(0, tprof_intel_establish_cpu, sc, NULL); 286 1.1 maxv xc_wait(xc); 287 1.1 maxv 288 1.1 maxv return 0; 289 1.1 maxv } 290 1.1 maxv 291 1.1 maxv static void 292 1.5 ryo tprof_intel_disestablish(tprof_backend_softc_t *sc) 293 1.1 maxv { 294 1.1 maxv uint64_t xc; 295 1.1 maxv 296 1.5 ryo xc = xc_broadcast(0, tprof_intel_disestablish_cpu, sc, NULL); 297 1.1 maxv xc_wait(xc); 298 1.1 maxv 299 1.1 maxv KASSERT(intel_nmi_handle != NULL); 300 1.1 maxv nmi_disestablish(intel_nmi_handle); 301 1.1 maxv intel_nmi_handle = NULL; 302 1.1 maxv } 303 1.1 maxv 304 1.2 maxv const tprof_backend_ops_t tprof_intel_ops = { 305 1.1 maxv .tbo_ident = tprof_intel_ident, 306 1.5 ryo .tbo_ncounters = tprof_intel_ncounters, 307 1.5 ryo .tbo_counter_bitwidth = tprof_intel_counter_bitwidth, 308 1.5 ryo .tbo_counter_read = tprof_intel_counter_read, 309 1.5 ryo .tbo_counter_estimate_freq = tprof_intel_counter_estimate_freq, 310 1.5 ryo .tbo_valid_event = NULL, 311 1.5 ryo .tbo_configure_event = tprof_intel_configure_event, 312 1.1 maxv .tbo_start = tprof_intel_start, 313 1.1 maxv .tbo_stop = tprof_intel_stop, 314 1.5 ryo .tbo_establish = tprof_intel_establish, 315 1.5 ryo .tbo_disestablish = tprof_intel_disestablish, 316 1.1 maxv }; 317