Linux Perf Users
 help / color / mirror / Atom feed
From: "Mi, Dapeng" <dapeng1.mi@linux.intel.com>
To: Peter Zijlstra <peterz@infradead.org>,
	Ian Rogers <irogers@google.com>,
	x86@kernel.org
Cc: Vince Weaver <vincent.weaver@maine.edu>,
	"Liang, Kan" <kan.liang@linux.intel.com>,
	linux-perf-users@vger.kernel.org
Subject: Re: perf_event: avoiding gpf on rdpmc for top-down-events on hybrid
Date: Thu, 5 Nov 2026 14:17:07 +0800	[thread overview]
Message-ID: <569b3882-5862-4f6f-96b7-302910e2cf4e@linux.intel.com> (raw)
In-Reply-To: <20250618084522.GE1613376@noisy.programming.kicks-ass.net>


On 6/18/2025 4:45 PM, Peter Zijlstra wrote:
> On Tue, Jun 17, 2025 at 01:36:40PM -0700, Ian Rogers wrote:
>
>> Thanks Peter, out of curiosity, how does the RDPMC fail? If an event
>> were rescheduled (even with RSEQ assuming the CPU the thread is
>> running on doesn't change) could the RDPMC with the incorrect index
>> also fail?
> So the problem with RDPMC is that it will #GP when used with an invalid
> index.
>
> Normally, when counting using fixed or general purpose events, this is
> not a problem, because every CPU in the machine has those. So while the
> index might not be the event you were after, the instruction doesn't
> trap, we observe the sequence changed and retry the loop. No harm done.
>
> But for the top-down thingies, the P-cores will have a RDPMC idx that
> the E-cores do not support. Using this index on an E-core will #GP.
>
> So the following situation:
>
> 	CPU-P				CPU-E
>
> 	do {
> 	  seq = pc->lock;
> 	  barrier();
>
> 	  index = pc->index;
> 	  count = pc->count;
> 	  if (index) {
> 	    width = pm->pmc_width;
> 	
> 			<migrate task to CPU-E>
>
> 					    rdpmc(index - 1); <-- #GP
> 					  }
>
> 					  barrier();
> 					} while (pc->lock != seq);
>
> Where the task is migrated from a P to an E core after reading the
> index but before doing RDPMC, turns fatal.
>
> When we use RSEQ, the migration will abort the sequence and the RDPMC
> will not be executed.
>
>
> Aand... while writing this I wondered why we don't simply fix up the
> fault in kernel space. Something like so...

If we silently drop the #GP for invalid rdpmc index, it would make the
kernel's behavior inconsistent with what SDM describes, "Specifying an
unsupported PMC encoding will cause a general protection exception #GP(0)."
It may break users' default assumption and cause some issues.


>
> ---
> diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
> index 9f88b8a78e50..90391526acf7 100644
> --- a/arch/x86/kernel/traps.c
> +++ b/arch/x86/kernel/traps.c
> @@ -677,6 +677,43 @@ static enum kernel_gp_hint get_kernel_gp_address(struct pt_regs *regs,
>  
>  #define GPFSTR "general protection fault"
>  
> +static bool fixup_rdpmc_exception(struct pt_regs *regs)
> +{
> +	struct mm_struct *mm = current->mm;
> +	u8 buf[MAX_INSN_SIZE];
> +	struct insn insn;
> +	int len;
> +
> +	len = insn_fetch_from_user(regs, buf);
> +	if (len <= 0)
> +		return false;
> +
> +	if (!insn_decode_from_regs(&insn, regs, buf, len))
> +		return false;
> +
> +	/* RDPMC */
> +	if (insn.opcode.bytes[0] != 0x0f || insn.opcode.bytes[1] != 0x33)
> +		return false;
> +
> +	if (!atomic_read(&mm->context.perf_rdpmc_allowed))
> +		return false;
> +
> +	/*
> +	 * So userspace RDPMC is allowed and took #GP.
> +	 *
> +	 * This means they got the index wrong. But per the ABI described in
> +	 * struct perf_event_mmap_page; this means they'll also fail the
> +	 * sequence lock and will retry the operation after re-reading the
> +	 * index.
> +	 *
> +	 * Fake out the RDPMC by returning all zeros and continue.
> +	 */
> +	regs->ax = 0;
> +	regs->dx = 0;
> +	regs->ip += insn.length;
> +	return true;
> +}
> +
>  static bool fixup_iopl_exception(struct pt_regs *regs)
>  {
>  	struct thread_struct *t = &current->thread;
> @@ -812,6 +849,9 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
>  	}
>  
>  	if (user_mode(regs)) {
> +		if (fixup_rdpmc_exception(regs))
> +			goto exit;
> +
>  		if (fixup_iopl_exception(regs))
>  			goto exit;
>  

      parent reply	other threads:[~2026-11-05  6:17 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-04 21:20 perf_event: avoiding gpf on rdpmc for top-down-events on hybrid Vince Weaver
2024-12-05  0:57 ` Ian Rogers
2025-06-15 23:23   ` Ian Rogers
2025-06-16 19:34     ` Vince Weaver
2025-06-17  4:36       ` Ian Rogers
2025-06-17 16:37         ` Ian Rogers
2025-06-17 18:17           ` Peter Zijlstra
2025-06-17 20:36             ` Ian Rogers
2025-06-18  8:45               ` Peter Zijlstra
2025-06-18 11:55                 ` Peter Zijlstra
2025-06-18 13:57                 ` Vince Weaver
2026-11-05  6:17                 ` Mi, Dapeng [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=569b3882-5862-4f6f-96b7-302910e2cf4e@linux.intel.com \
    --to=dapeng1.mi@linux.intel.com \
    --cc=irogers@google.com \
    --cc=kan.liang@linux.intel.com \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=peterz@infradead.org \
    --cc=vincent.weaver@maine.edu \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox