1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci 3f08c3bdfSopenharmony_ci/* 4f08c3bdfSopenharmony_ci * Copyright (C) 2018 Intel Corporation 5f08c3bdfSopenharmony_ci * Author: Ammy Yi (ammy.yi@intel.com) 6f08c3bdfSopenharmony_ci */ 7f08c3bdfSopenharmony_ci 8f08c3bdfSopenharmony_ci/* 9f08c3bdfSopenharmony_ci * This test will check if Intel PT(Intel Processer Trace) is working. 10f08c3bdfSopenharmony_ci * 11f08c3bdfSopenharmony_ci * Intel CPU of 5th-generation Core (Broadwell) or newer is required for the test. 12f08c3bdfSopenharmony_ci * 13f08c3bdfSopenharmony_ci * kconfig requirement: CONFIG_PERF_EVENTS 14f08c3bdfSopenharmony_ci */ 15f08c3bdfSopenharmony_ci 16f08c3bdfSopenharmony_ci 17f08c3bdfSopenharmony_ci#include <sched.h> 18f08c3bdfSopenharmony_ci#include <stdlib.h> 19f08c3bdfSopenharmony_ci#include <stdio.h> 20f08c3bdfSopenharmony_ci#include <string.h> 21f08c3bdfSopenharmony_ci#include "tst_test.h" 22f08c3bdfSopenharmony_ci#include "lapi/syscalls.h" 23f08c3bdfSopenharmony_ci#include "config.h" 24f08c3bdfSopenharmony_ci 25f08c3bdfSopenharmony_ci#ifdef HAVE_STRUCT_PERF_EVENT_MMAP_PAGE_AUX_HEAD 26f08c3bdfSopenharmony_ci# include <linux/perf_event.h> 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_ci#define PAGESIZE 4096 29f08c3bdfSopenharmony_ci#define INTEL_PT_MEMSIZE (17*PAGESIZE) 30f08c3bdfSopenharmony_ci 31f08c3bdfSopenharmony_ci#define BIT(nr) (1UL << (nr)) 32f08c3bdfSopenharmony_ci 33f08c3bdfSopenharmony_ci#define INTEL_PT_PATH "/sys/devices/intel_pt" 34f08c3bdfSopenharmony_ci#define INTEL_PT_PMU_TYPE "/sys/devices/intel_pt/type" 35f08c3bdfSopenharmony_ci#define INTEL_PT_FORMAT_TSC "/sys/devices/intel_pt/format/tsc" 36f08c3bdfSopenharmony_ci#define INTEL_PT_FORMAT_NRT "/sys/devices/intel_pt/format/noretcomp" 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_ci//Intel PT event handle 39f08c3bdfSopenharmony_ciint fde = -1; 40f08c3bdfSopenharmony_ci//map head and size 41f08c3bdfSopenharmony_ciuint64_t **bufm; 42f08c3bdfSopenharmony_cilong buhsz; 43f08c3bdfSopenharmony_cistatic char *str_mode; 44f08c3bdfSopenharmony_cistatic char *str_exclude_info; 45f08c3bdfSopenharmony_cistatic char *str_branch_flag; 46f08c3bdfSopenharmony_ciint mode = 1; 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_cistatic uint64_t **create_map(int fde, long bufsize, int flag) 49f08c3bdfSopenharmony_ci{ 50f08c3bdfSopenharmony_ci uint64_t **buf_ev; 51f08c3bdfSopenharmony_ci int pro_flag; 52f08c3bdfSopenharmony_ci struct perf_event_mmap_page *pc; 53f08c3bdfSopenharmony_ci 54f08c3bdfSopenharmony_ci buf_ev = SAFE_MALLOC(2*sizeof(uint64_t *)); 55f08c3bdfSopenharmony_ci buf_ev[0] = NULL; 56f08c3bdfSopenharmony_ci buf_ev[1] = NULL; 57f08c3bdfSopenharmony_ci if (flag == 1) { 58f08c3bdfSopenharmony_ci tst_res(TINFO, "Memory will be r/w for full trace mode"); 59f08c3bdfSopenharmony_ci pro_flag = PROT_READ | PROT_WRITE; 60f08c3bdfSopenharmony_ci } else { 61f08c3bdfSopenharmony_ci tst_res(TINFO, "Memory will be r only for snapshot mode"); 62f08c3bdfSopenharmony_ci pro_flag = PROT_READ; 63f08c3bdfSopenharmony_ci } 64f08c3bdfSopenharmony_ci buf_ev[0] = SAFE_MMAP(NULL, INTEL_PT_MEMSIZE, PROT_READ | PROT_WRITE, 65f08c3bdfSopenharmony_ci MAP_SHARED, fde, 0); 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_ci tst_res(TINFO, "Open Intel PT event failed"); 68f08c3bdfSopenharmony_ci pc = (struct perf_event_mmap_page *)buf_ev[0]; 69f08c3bdfSopenharmony_ci pc->aux_offset = INTEL_PT_MEMSIZE; 70f08c3bdfSopenharmony_ci pc->aux_size = bufsize; 71f08c3bdfSopenharmony_ci buf_ev[1] = SAFE_MMAP(NULL, bufsize, pro_flag, 72f08c3bdfSopenharmony_ci MAP_SHARED, fde, INTEL_PT_MEMSIZE); 73f08c3bdfSopenharmony_ci return buf_ev; 74f08c3bdfSopenharmony_ci} 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ciint intel_pt_pmu_value(char *dir) 78f08c3bdfSopenharmony_ci{ 79f08c3bdfSopenharmony_ci char *value; 80f08c3bdfSopenharmony_ci int val = 0; 81f08c3bdfSopenharmony_ci char delims[] = ":"; 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_ci SAFE_FILE_SCANF(dir, "%m[^\n]", &value); 84f08c3bdfSopenharmony_ci if (strstr(value, delims) == NULL) { 85f08c3bdfSopenharmony_ci val = atoi(value); 86f08c3bdfSopenharmony_ci } else { 87f08c3bdfSopenharmony_ci strsep(&value, delims); 88f08c3bdfSopenharmony_ci val = atoi(value); 89f08c3bdfSopenharmony_ci } 90f08c3bdfSopenharmony_ci return val; 91f08c3bdfSopenharmony_ci} 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_cistatic void del_map(uint64_t **buf_ev, long bufsize) 94f08c3bdfSopenharmony_ci{ 95f08c3bdfSopenharmony_ci if (buf_ev) { 96f08c3bdfSopenharmony_ci if (buf_ev[0]) 97f08c3bdfSopenharmony_ci munmap(buf_ev[0], INTEL_PT_MEMSIZE); 98f08c3bdfSopenharmony_ci if (buf_ev[1]) 99f08c3bdfSopenharmony_ci munmap(buf_ev[1], bufsize); 100f08c3bdfSopenharmony_ci } 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_ci free(buf_ev); 103f08c3bdfSopenharmony_ci} 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_cistatic void intel_pt_trace_check(void) 106f08c3bdfSopenharmony_ci{ 107f08c3bdfSopenharmony_ci uint64_t aux_head = 0; 108f08c3bdfSopenharmony_ci struct perf_event_mmap_page *pmp; 109f08c3bdfSopenharmony_ci /* enable tracing */ 110f08c3bdfSopenharmony_ci SAFE_IOCTL(fde, PERF_EVENT_IOC_RESET); 111f08c3bdfSopenharmony_ci SAFE_IOCTL(fde, PERF_EVENT_IOC_ENABLE); 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_ci /* stop tracing */ 114f08c3bdfSopenharmony_ci SAFE_IOCTL(fde, PERF_EVENT_IOC_DISABLE); 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci /* check if there is some trace generated */ 117f08c3bdfSopenharmony_ci pmp = (struct perf_event_mmap_page *)bufm[0]; 118f08c3bdfSopenharmony_ci aux_head = *(volatile uint64_t *)&pmp->aux_head; 119f08c3bdfSopenharmony_ci if (aux_head == 0) { 120f08c3bdfSopenharmony_ci tst_res(TFAIL, "There is no trace"); 121f08c3bdfSopenharmony_ci return; 122f08c3bdfSopenharmony_ci } 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci tst_res(TPASS, "perf trace test passed"); 125f08c3bdfSopenharmony_ci} 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_cistatic int is_affected_by_erratum_BDM106(void) 128f08c3bdfSopenharmony_ci{ 129f08c3bdfSopenharmony_ci int family = -1, model = -1; 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci if (FILE_LINES_SCANF("/proc/cpuinfo", "cpu family%*s%d", &family) 132f08c3bdfSopenharmony_ci || family != 6) 133f08c3bdfSopenharmony_ci return 0; 134f08c3bdfSopenharmony_ci 135f08c3bdfSopenharmony_ci if (!FILE_LINES_SCANF("/proc/cpuinfo", "model%*s%d", &model)) { 136f08c3bdfSopenharmony_ci tst_res(TINFO, "Intel FAM6 model %d", model); 137f08c3bdfSopenharmony_ci 138f08c3bdfSopenharmony_ci switch (model) { 139f08c3bdfSopenharmony_ci case 0x3D: /* INTEL_FAM6_BROADWELL */ 140f08c3bdfSopenharmony_ci /* fallthrough */ 141f08c3bdfSopenharmony_ci case 0x47: /* INTEL_FAM6_BROADWELL_G */ 142f08c3bdfSopenharmony_ci /* fallthrough */ 143f08c3bdfSopenharmony_ci case 0x4F: /* INTEL_FAM6_BROADWELL_X */ 144f08c3bdfSopenharmony_ci /* fallthrough */ 145f08c3bdfSopenharmony_ci case 0x56: /* INTEL_FAM6_BROADWELL_D */ 146f08c3bdfSopenharmony_ci return 1; 147f08c3bdfSopenharmony_ci } 148f08c3bdfSopenharmony_ci } 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci return 0; 151f08c3bdfSopenharmony_ci} 152f08c3bdfSopenharmony_ci 153f08c3bdfSopenharmony_cistatic void setup(void) 154f08c3bdfSopenharmony_ci{ 155f08c3bdfSopenharmony_ci struct perf_event_attr attr = {}; 156f08c3bdfSopenharmony_ci 157f08c3bdfSopenharmony_ci buhsz = 2 * PAGESIZE; 158f08c3bdfSopenharmony_ci 159f08c3bdfSopenharmony_ci if (access(INTEL_PT_PATH, F_OK)) { 160f08c3bdfSopenharmony_ci tst_brk(TCONF, 161f08c3bdfSopenharmony_ci "Requires Intel Core 5th+ generation (Broadwell and newer) and CONFIG_PERF_EVENTS enabled"); 162f08c3bdfSopenharmony_ci } 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_ci /* set attr for Intel PT trace */ 165f08c3bdfSopenharmony_ci attr.type = intel_pt_pmu_value(INTEL_PT_PMU_TYPE); 166f08c3bdfSopenharmony_ci attr.read_format = PERF_FORMAT_ID | PERF_FORMAT_TOTAL_TIME_RUNNING | 167f08c3bdfSopenharmony_ci PERF_FORMAT_TOTAL_TIME_ENABLED; 168f08c3bdfSopenharmony_ci attr.disabled = 1; 169f08c3bdfSopenharmony_ci attr.config = BIT(intel_pt_pmu_value(INTEL_PT_FORMAT_TSC)) | 170f08c3bdfSopenharmony_ci BIT(intel_pt_pmu_value(INTEL_PT_FORMAT_NRT)); 171f08c3bdfSopenharmony_ci attr.size = sizeof(struct perf_event_attr); 172f08c3bdfSopenharmony_ci attr.mmap = 1; 173f08c3bdfSopenharmony_ci if (str_branch_flag) { 174f08c3bdfSopenharmony_ci if (is_affected_by_erratum_BDM106()) { 175f08c3bdfSopenharmony_ci tst_brk(TCONF, "erratum BDM106 disallows not " 176f08c3bdfSopenharmony_ci "setting BRANCH_EN on this CPU"); 177f08c3bdfSopenharmony_ci } 178f08c3bdfSopenharmony_ci 179f08c3bdfSopenharmony_ci tst_res(TINFO, "Intel PT will disable branch trace"); 180f08c3bdfSopenharmony_ci attr.config |= 1; 181f08c3bdfSopenharmony_ci } 182f08c3bdfSopenharmony_ci 183f08c3bdfSopenharmony_ci attr.exclude_kernel = 0; 184f08c3bdfSopenharmony_ci attr.exclude_user = 0; 185f08c3bdfSopenharmony_ci if (str_exclude_info) { 186f08c3bdfSopenharmony_ci if (!strcmp(str_exclude_info, "user")) { 187f08c3bdfSopenharmony_ci tst_res(TINFO, "Intel PT will exclude user trace"); 188f08c3bdfSopenharmony_ci attr.exclude_user = 1; 189f08c3bdfSopenharmony_ci } else if (!strcmp(str_exclude_info, "kernel")) { 190f08c3bdfSopenharmony_ci tst_res(TINFO, "Intel PT will exclude kernel trace"); 191f08c3bdfSopenharmony_ci attr.exclude_kernel = 1; 192f08c3bdfSopenharmony_ci } else { 193f08c3bdfSopenharmony_ci tst_brk(TBROK, "Invalid -e '%s'", str_exclude_info); 194f08c3bdfSopenharmony_ci } 195f08c3bdfSopenharmony_ci } 196f08c3bdfSopenharmony_ci 197f08c3bdfSopenharmony_ci /* only get trace for own pid */ 198f08c3bdfSopenharmony_ci fde = tst_syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); 199f08c3bdfSopenharmony_ci if (fde < 0) { 200f08c3bdfSopenharmony_ci tst_res(TINFO, "Open Intel PT event failed"); 201f08c3bdfSopenharmony_ci tst_res(TFAIL, "perf trace full mode failed"); 202f08c3bdfSopenharmony_ci return; 203f08c3bdfSopenharmony_ci } 204f08c3bdfSopenharmony_ci bufm = NULL; 205f08c3bdfSopenharmony_ci if (str_mode) 206f08c3bdfSopenharmony_ci mode = 0; 207f08c3bdfSopenharmony_ci 208f08c3bdfSopenharmony_ci bufm = create_map(fde, buhsz, mode); 209f08c3bdfSopenharmony_ci} 210f08c3bdfSopenharmony_ci 211f08c3bdfSopenharmony_cistatic void cleanup(void) 212f08c3bdfSopenharmony_ci{ 213f08c3bdfSopenharmony_ci if (fde != -1) 214f08c3bdfSopenharmony_ci close(fde); 215f08c3bdfSopenharmony_ci 216f08c3bdfSopenharmony_ci del_map(bufm, buhsz); 217f08c3bdfSopenharmony_ci} 218f08c3bdfSopenharmony_ci 219f08c3bdfSopenharmony_cistatic struct tst_test test = { 220f08c3bdfSopenharmony_ci .test_all = intel_pt_trace_check, 221f08c3bdfSopenharmony_ci .options = (struct tst_option[]) { 222f08c3bdfSopenharmony_ci {"m", &str_mode, "Different mode, default is full mode"}, 223f08c3bdfSopenharmony_ci {"e:", &str_exclude_info, "Exclude info, user or kernel"}, 224f08c3bdfSopenharmony_ci {"b", &str_branch_flag, "Disable branch trace"}, 225f08c3bdfSopenharmony_ci {} 226f08c3bdfSopenharmony_ci }, 227f08c3bdfSopenharmony_ci .min_kver = "4.1", 228f08c3bdfSopenharmony_ci .setup = setup, 229f08c3bdfSopenharmony_ci .cleanup = cleanup, 230f08c3bdfSopenharmony_ci .needs_root = 1, 231f08c3bdfSopenharmony_ci}; 232f08c3bdfSopenharmony_ci 233f08c3bdfSopenharmony_ci#else 234f08c3bdfSopenharmony_ciTST_TEST_TCONF("Missing aux_* fields in struct perf_event_mmap_page"); 235f08c3bdfSopenharmony_ci#endif /* HAVE_STRUCT_PERF_EVENT_MMAP_PAGE_AUX_HEAD */ 236