From 79256d37e4b166e1dac8bbb806151735459c72ea Mon Sep 17 00:00:00 2001 From: Xudong Hao Date: Thu, 26 Mar 2026 11:04:48 +0800 Subject: [PATCH 1/2] BM/PMU: add rdpmc-user-disable test tool DMR/NVL introduces rdpmc user disable feature to mitigate the security risk that user space tool could directly read the count of system-wide events. About the support details of rdpmc user disable in kernek, please refer https://lore.kernel.org/all/20260114011750.350569-8-dapeng1.mi@linux.intel.com/ usage: rdpmc_user_disable_test Signed-off-by: Xudong Hao Signed-off-by: Dapeng Mi --- BM/pmu/Makefile | 11 ++ BM/pmu/rdpmc_user_disable_test.c | 182 +++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 BM/pmu/Makefile create mode 100644 BM/pmu/rdpmc_user_disable_test.c diff --git a/BM/pmu/Makefile b/BM/pmu/Makefile new file mode 100644 index 00000000..2a85a00c --- /dev/null +++ b/BM/pmu/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2026 Intel Corporation. + +CC = gcc +TARGET = rdpmc_user_disable_test + +$(TARGET): rdpmc_user_disable_test.c + $(CC) -o $@ $< + +clean: + rm -f $(TARGET) diff --git a/BM/pmu/rdpmc_user_disable_test.c b/BM/pmu/rdpmc_user_disable_test.c new file mode 100644 index 00000000..dc540147 --- /dev/null +++ b/BM/pmu/rdpmc_user_disable_test.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2026 Intel Corporation. + +#define LINUX +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned long long u64; +int pagesize; + +// Read memory barrier +#define rmb() asm volatile("" ::: "memory") + +struct cpu { + int fd; + struct perf_event_mmap_page *buf; +}; + +int perf_open(struct cpu *ctx, int cpu, unsigned int counter, int pid) +{ + int ret; + + struct perf_event_attr attr = { + .type = PERF_TYPE_RAW, + .size = sizeof(struct perf_event_attr), + .config = counter, + .sample_type = PERF_SAMPLE_READ, + .precise_ip = 0, + }; + + ctx->buf = NULL; + ctx->fd = syscall(__NR_perf_event_open, &attr, pid, cpu, -1, 0); + if (ctx->fd < 0) { + printf("Failed to open event 0x%x err %d\n", counter, ctx->fd); + return -1; + } + + ctx->buf = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, ctx->fd, 0); + if (ctx->buf == MAP_FAILED) { + close(ctx->fd); + printf("Failed to mmap event 0x%x\n", counter); + return -1; + } + + ret = ioctl(ctx->fd, PERF_EVENT_IOC_ENABLE, 0); + if (ret < 0) { + printf("Failed to enable event 0x%x\n", counter); + return -1; + } + + return 0; +} + +void perf_close(struct cpu *ctx) +{ + close(ctx->fd); + if (ctx->buf) + munmap(ctx->buf, pagesize); +} + +unsigned long long perf_read(struct cpu *ctx) +{ + u64 val; + unsigned int seq; + u64 offset; + typeof(ctx->buf) buf = ctx->buf; + + do { + seq = buf->lock; + /* Pairs with the rmb below in perf_read */ + rmb(); + /* XXX fallback */ + val = __builtin_ia32_rdpmc(buf->index - 1); + offset = buf->offset; + /* Pairs with the rmb above in perf_read */ + rmb(); + } while (buf->lock != seq); + return val; +} + +void gp_fault_handler(int sig, siginfo_t *si, void *unused) +{ + printf("Receive and handle #GP fault\n"); + exit(-2); +} + +int main(int argc, const char **argv) +{ + struct sigaction sa; + cpu_set_t cpuset; + struct cpu cpu; + unsigned int counter; + u64 count; + int cpuid; + int pid; + int ret; + + if (argc != 4) { + printf("Usage: %s \n", argv[0]); + return -1; + } + + if (!strncmp(argv[2], "system", 6)) + pid = -1; + else if (!strncmp(argv[2], "process", 7)) + pid = 0; + else { + printf("Usage: %s \n", argv[0]); + return -1; + } + + if (!strncmp(argv[3], "gp", 6)) + counter = 0xc4; /* branches */ + else if (!strncmp(argv[3], "fixed", 5)) + counter = 0xc0; /* instructions */ + else { + printf("Usage: %s \n", argv[0]); + return -1; + } + + cpuid = atoi(argv[1]); + + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = gp_fault_handler; + + if (sigaction(SIGSEGV, &sa, NULL) == -1) { + printf("Fail to set the #GP handler\n"); + return -1; + } + + CPU_ZERO(&cpuset); + CPU_SET(cpuid, &cpuset); + if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) == -1) { + printf("Fail to bind the program to cpu %d\n", cpuid); + return -1; + } + + pagesize = sysconf(_SC_PAGESIZE); + + /* open & enable event */ + ret = perf_open(&cpu, cpuid, counter, pid); + if (ret < 0) + goto err; + + /* do something here */ + sleep(1); + + /* read event */ + count = perf_read(&cpu); + + /* disable event */ + ret = ioctl(cpu.fd, PERF_EVENT_IOC_DISABLE, 0); + if (ret < 0) { + printf("Failed to disable event 0x%x\n", counter); + goto err; + } + + /* close event */ + perf_close(&cpu); + + printf("CPU %d - %s %s event (0x%x) count %lld\n", + cpuid, argv[2], argv[3], counter, count); + + return count; + +err: + printf("rdpmc-user-disable test case: CPU %d - %s %s event (0x%x) FAIL!\n", + cpuid, argv[2], argv[3], counter); + return -1; +} From 59f5c6041a79b82c473b0e5578d2916d5d4ae751 Mon Sep 17 00:00:00 2001 From: Xudong Hao Date: Thu, 26 Mar 2026 11:23:28 +0800 Subject: [PATCH 2/2] BM/PMU: Add rdpmc user disable test cases Signed-off-by: Xudong Hao --- BM/pmu/pmu_tests.sh | 62 +++++++++++++++++++++++++++++++++++++++++++++ BM/pmu/tests_dmr | 38 +++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 BM/pmu/tests_dmr diff --git a/BM/pmu/pmu_tests.sh b/BM/pmu/pmu_tests.sh index d2b069c0..04bf48d4 100755 --- a/BM/pmu/pmu_tests.sh +++ b/BM/pmu/pmu_tests.sh @@ -475,6 +475,59 @@ counting_multi_test() { done } +rdpmc_user_disable() { + local logfile1="temp1.log" + local logfile2="temp2.log" + local logfile3="temp3.log" + local logfile4="temp4.log" + #23H.00H:EBX[2]: RDPMC_USR_DISABLE + do_cmd "cpuid_check 23 0 0 0 b 2" + [ $? -ne 0 ] && die "Platform does not support RDPMC USR DISABLE feature" + + rdpmc_attr=$1 + echo $rdpmc_attr > /sys/devices/cpu/rdpmc + + clear_files $logfile1 $logfile2 $logfile3 $logfile4 + [ -f rdpmc_user_disable_test ] || die "please compile rdpmc_user_disable_test firstly " + rdpmc_user_disable_test 0 system gp > $logfile1 + rdpmc_user_disable_test 0 system fixed > $logfile2 + rdpmc_user_disable_test 0 process gp > $logfile3 + rdpmc_user_disable_test 0 process fixed > $logfile4 + case $rdpmc_attr in + 0) + for file in $logfile1 $logfile2 $logfile3 $logfile4; + do + cat $file | grep "Receive and handle #GP fault" + [ $? -eq 0 ] || die "rdpmc user disable test fail with rdpmc 0" + clear_files $file + done + ;; + 1) + for file in $logfile1 $logfile2; + do + num=$(cat $file | awk '{print $NF}') + clear_files $file + [ $num -eq 0 ] || die "rdpmc user disable test fail with rdpmc 1" + done + + for file in $logfile3 $logfile4; + do + num=$(cat $file | awk '{print $NF}') + clear_files $file + [ $num -gt 0 ] || die "rdpmc user disable test fail with rdpmc 1" + done + ;; + 2) + for file in $logfile1 $logfile2 $logfile3 $logfile4; + do + num=$(cat $file | awk '{print $NF}') + clear_files $file + [ $num -gt 0 ] || die "rdpmc user disable test fail with rdpmc 2" + done + ;; + esac +} + pmu_test() { case $TEST_SCENARIO in fix_counter) @@ -549,6 +602,15 @@ pmu_test() { counting_multi) counting_multi_test ;; + rdpmc_user_disable_0) + rdpmc_user_disable 0 + ;; + rdpmc_user_disable_1) + rdpmc_user_disable 1 + ;; + rdpmc_user_disable_2) + rdpmc_user_disable 2 + ;; esac return 0 } diff --git a/BM/pmu/tests_dmr b/BM/pmu/tests_dmr new file mode 100644 index 00000000..3b420aac --- /dev/null +++ b/BM/pmu/tests_dmr @@ -0,0 +1,38 @@ +# This file collects the PMU cases for DMR platform +pmu_tests.sh -t basic +pmu_tests.sh -t uncore +pmu_tests.sh -t uncore_dmesg +pmu_tests.sh -t uncore_events +pmu_iommu_tests.sh -t iommu_clocks +pmu_iommu_tests.sh -t iommu_all_basic +apebs_tests.sh -t data_src -w 0 +apebs_tests.sh -t ip_1 -w 0 +apebs_tests.sh -t ip_2 -w 0 +apebs_tests.sh -t lbr_1 -w 0 +apebs_tests.sh -t lbr_2 -w 0 +apebs_tests.sh -t large_pebs -w 0 +apebs_tests.sh -t large_pebs -w 1 +apebs_tests.sh -t xmm_1 -w 1 +apebs_tests.sh -t xmm_2 -w 1 +apebs_tests.sh -t ip_1 -w 1 +apebs_tests.sh -t ip_2 -w 1 +apebs_tests.sh -t data_src -w 1 +apebs_tests.sh -t lbr_1 -w 1 +apebs_tests.sh -t lbr_2 -w 1 +apebs_tests.sh -t ip_1 -w 1 +apebs_tests.sh -t ip_2 -w 1 +apebs_tests.sh -t data_src -w 1 +pmu_tests.sh -t timed_pebs_msr +pmu_tests.sh -t lbr_events_cpuid +pmu_tests.sh -t lbr_events_s +pmu_tests.sh -t lbr_events_all +pmu_tests.sh -t arch_pebs_cpuid +pmu_tests.sh -t arch_pebs_gp_reg_group +pmu_tests.sh -t arch_pebs_xer_group +pmu_tests.sh -t arch_pebs_counter_group +pmu_tests.sh -t arch_pebs_counter_group_stress +pmu_tests.sh -t arch_pebs_gp_counter +pmu_tests.sh -t arch_pebs_basic_group +pmu_tests.sh -t rdpmc_user_disable_0 +pmu_tests.sh -t rdpmc_user_disable_1 +pmu_tests.sh -t rdpmc_user_disable_2