RE: [patch 3/3] x86/fpu: Make FPU protection more robust

From: David Laight
Date: Thu May 05 2022 - 07:54:25 EST




> -----Original Message-----
> From: Jason A. Donenfeld <Jason@xxxxxxxxx>
> Sent: 05 May 2022 12:36
> To: David Laight <David.Laight@xxxxxxxxxx>
> Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>; Peter Zijlstra <peterz@xxxxxxxxxxxxx>; Borislav Petkov
> <bp@xxxxxxxxx>; LKML <linux-kernel@xxxxxxxxxxxxxxx>; x86@xxxxxxxxxx; Filipe Manana
> <fdmanana@xxxxxxxx>; linux-crypto@xxxxxxxxxxxxxxx
> Subject: Re: [patch 3/3] x86/fpu: Make FPU protection more robust
>
> On Thu, May 5, 2022 at 1:34 PM David Laight <David.Laight@xxxxxxxxxx> wrote:
> >
> > ...
> > > + cycles_t end, start = get_cycles();
> > > blake2s_update(&input_pool.hash, in, nbytes);
> > > + end = get_cycles();
> >
> > If get_cycles() is rdtsc then that gives meaningless numbers.
> > The cpu clock frequency will change on you.
> >
> > You can use one of the performance counters to get an actual
>
> Indeed. In the process of wiring up rdpmc now.

I've used this before now.
But the loop getting the pmc value in non-deterministic.
So I sometimes remove it.
Also you need to add a serialising instruction - otherwise
the pmc get read before the code you are measuring
actually finishes.

I've used similar code to measure iterations on the ip checksum code.
Can show how many bytes/clock that achieves in its inner loop.
Which can match what you might expect the instructions to generate.

David

static inline unsigned int rdpmc(unsigned int counter)
{
unsigned int low, high;

asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));

// return low bits, counter might to 32 or 40 bits wide.
return low;
}

static inline unsigned int rdtsc(void)
{
unsigned int low, high;

asm volatile("rdtsc" : "=a" (low), "=d" (high));

return low;
}

unsigned int read_cpu_cycles(void)
{
static struct perf_event_attr perf_attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
.pinned = 1,
};
static __thread struct perf_event_mmap_page *pc;
static int pmc_failed;

unsigned int seq, idx, count;

if (pmc_failed)
return rdtsc();

if (!pc) {
int perf_fd;
perf_fd = syscall(__NR_perf_event_open, &perf_attr, 0, -1, -1, 0);
if (perf_fd < 0) {
pmc_failed = 1;
return rdtsc();
}
pc = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_READ, MAP_SHARED, perf_fd, 0);
close(perf_fd);
if (pc == MAP_FAILED) {
pmc_failed = 1;
return rdtsc();
}
}

do {
seq = pc->lock;
asm volatile("":::"memory");
idx = pc->index;
if (!idx) // || !pc->cap_user_rdpmc)
return 0;
count = pc->offset + rdpmc(idx - 1);
asm volatile("":::"memory");
} while (pc->lock != seq);

return count;
}

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)