Re: [PATCH 1/1] perf/x86: Do not read fixed counter control register if there is none

"Tony W Wang-oc" <[email protected]> Wed, 5 Aug 2026 19:39:40 +0800
Newsgroups org.kernel.vger.linux-perf-users,dev.linux.lists.sashiko-reviews,org.kernel.vger.linux-kernel
Message-ID <[email protected]>

On 2026/7/17 23:51, Petr Tesarik wrote:
> On Fri, 17 Jul 2026 15:18:58 +0000
> [email protected] wrote:
> 
>> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
>>
>> New issues:
>> - [Medium] Using `x86_pmu.fixedctr` as a capability flag is conceptually flawed and suppresses valid debug output on Zhaoxin.
>>
>> Pre-existing issues:
>> - [High] Zhaoxin PMU fails to initialize `x86_pmu.fixedctr`, leading to broken fixed counters and unsafe RDMSR accesses.
>> - [High] Undefined behavior in `GENMASK_ULL` during Zhaoxin PMU initialization if fixed counters are missing.
>> --
>>
>> --- Patch [1]: [PATCH 1/1] perf/x86: Do not read fixed counter control register if there is none ---
>> commit d0dd53a6709a65141e2d105b19abad4d851825d4
>> Author: Petr Tesarik <[email protected]>
>>
>> perf/x86: Do not read fixed counter control register if there is none
>>
>> This patch skips reading the MSR_ARCH_PERFMON_FIXED_CTR_CTRL register
>> during perf debug output if fixed counters are not implemented. This avoids
>> a #GP on AMD CPUs with PerfMonV2 that do not implement this register.
>>
>>> diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
>>> index 576baa9a52c5b..3055d59e0e82f 100644
>>> --- a/arch/x86/events/core.c
>>> +++ b/arch/x86/events/core.c
>>> @@ -1572,13 +1572,16 @@ void perf_event_print_debug(void)
>>>   		rdmsrq(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
>>>   		rdmsrq(MSR_CORE_PERF_GLOBAL_STATUS, status);
>>>   		rdmsrq(MSR_CORE_PERF_GLOBAL_OVF_CTRL, overflow);
>>> -		rdmsrq(MSR_ARCH_PERFMON_FIXED_CTR_CTRL, fixed);
>>>   
>>>   		pr_info("\n");
>>>   		pr_info("CPU#%d: ctrl:       %016llx\n", cpu, ctrl);
>>>   		pr_info("CPU#%d: status:     %016llx\n", cpu, status);
>>>   		pr_info("CPU#%d: overflow:   %016llx\n", cpu, overflow);
>>> -		pr_info("CPU#%d: fixed:      %016llx\n", cpu, fixed);
>>> +
>>> +		if (x86_pmu.fixedctr) {
>>
>> [Severity: Medium]
>> Is it safe to use x86_pmu.fixedctr as a capability flag here?
> 
> Good question. In fact, I thought about it, and yes, introducing a new
> flag would be the cleanest solution, but it seemed overkill just for
> this debugging output.
> 
> AFAIK the MSR offset of the fixed perf counters cannot be zero, because
> those MSR addresses have been assigned to other architectural MSRs since
> Pentium times...
> 
>> The x86_pmu.fixedctr field is an MSR address, not a boolean capability
>> flag. While this check works for most architectures, the Zhaoxin PMU driver
>> fails to initialize this field, leaving it as 0. Because of this, the check
>> evaluates to false and inadvertently suppresses the debug output of
>> MSR_ARCH_PERFMON_FIXED_CTR_CTRL on Zhaoxin systems.
> 
> I don't know about Zhaoxin. Do these syste have fixed performance
> counters and a corresponding global control register?
> 
Yes, Zhaoxin system have fixed performance counters and a corresponding 
global control register.

> Adding Tony W Wang to the recipient list...
> 
> Petr T
> 
> --
> 
>>> +			rdmsrq(MSR_ARCH_PERFMON_FIXED_CTR_CTRL,
>>> fixed);
>>> +			pr_info("CPU#%d: fixed:      %016llx\n",
>>> cpu, fixed);
>>> +		}
>>>   		if (pebs_constraints) {
>>>   			rdmsrq(MSR_IA32_PEBS_ENABLE, pebs);
>>>   			pr_info("CPU#%d: pebs:       %016llx\n",
>>> cpu, pebs);
>> [ ... ]
>>
>>
>> [Severity: High]
>> This is a pre-existing issue and was not introduced by the patch under
>> review, but the lack of initialization for x86_pmu.fixedctr causes
>> other issues.
>>
>> In the Zhaoxin PMU driver setup:
>>
>> arch/x86/events/zhaoxin/core.c:zhaoxin_pmu
>> static const struct x86_pmu zhaoxin_pmu __initconst = {
>>      ...
>>      /* missing .fixedctr = MSR_ARCH_PERFMON_FIXED_CTR0 */
>> };
>>
This issue has indeed resulted in an “perf -e instructions” bug on 
Zhaoxin processors. Although Tanze submitted a patch in 2025, it seems 
it has not yet been merged to mainstream.
https://lkml.org/lkml/2025/6/19/141


>> Because this remains 0, x86_pmu_fixed_ctr_addr() returns 0 + idx
>> instead of the correct MSR. This causes fixed counter 0 to silently
>> return without updating in x86_perf_event_update():
>>
>> arch/x86/events/core.c:x86_perf_event_update() {
>>      ...
>>      if (unlikely(!hwc->event_base))
>>          return 0;
>>      ...
>> }
>>
>> It also leads to unsafe MSR reads when iterating over the fixed
>> counter mask in perf_event_print_debug():
>>
>> arch/x86/events/core.c:perf_event_print_debug() {
>>      ...
>>      for_each_set_bit(idx, fixed_cntr_mask, X86_PMC_IDX_MAX) {
>>          ...
>>          rdmsrq(x86_pmu_fixed_ctr_addr(idx), pmc_count);
>>          ...
>>      }
>> }
>>
>> Could this lead to reads from arbitrary low MSRs like MSR 0, 1, or 2,
>> potentially triggering a system crash if a user programs fixed counter
>> events or triggers SysRq-P?
>>
>>
>> [Severity: High]
>> This is a pre-existing issue and was not introduced by the patch under
>> review, but does this bitmask generation in the Zhaoxin PMU
>> initialization risk undefined behavior?
>>
>> arch/x86/events/zhaoxin/core.c:zhaoxin_pmu_init() {
>>      ...
>>      x86_pmu.fixed_cntr_mask64 =
>> GENMASK_ULL(edx.split.num_counters_fixed - 1, 0); ...
>> }
>>
>> If a hypervisor configures the CPU to report 0 fixed counters,
>> edx.split.num_counters_fixed - 1 wraps to -1. Expanding
>> GENMASK_ULL(-1, 0) results in a right-shift by 64, which is undefined
>> behavior in C. On x86, this yields ~0ULL, making the kernel assume 64
>> fixed counters exist.
>>
>> Could this cause the kernel to attempt reading 64 undefined MSRs
>> during debug output or event initialization, leading to #GP
>> exceptions?
>>
This issue may exist. Can the code be changed as follows?

if (edx.split.num_counters_fixed == 0) {
     x86_pmu.fixed_cntr_mask64 = 0;
} else {
     x86_pmu.fixed_cntr_mask64 = 
GENMASK_ULL(edx.split.num_counters_fixed - 1, 0);
}


In addition, this issue also appears to exist in the Intel PMU driver, 
should we fix them together?

Sincerely!
TonyWWang-oc