Re: Direct rdtsc call side-effect

Steven Noonan
2023-06-01T21:41:48Z

[-- Attachment #1.1: Type: text/plain, Size: 952 bytes --]

On Thursday, June 1st, 2023 at 1:31 PM, Peter Zijlstra <peterz@infradead.org> wrote:
> What about kernel based emulation? You could tie it into user_dispatch
> and have a user_dispatch tsc offset.
>

> So regular kernel emulation simply returns the native value (keeps the
> VDSO working for one), but then from a user_dispatch range, it returns
> +offset.
>

> That is; how slow is the below?

It's around 1800-1900 clock cycles on this system (modified patch attached, compile fix + rdtscp support).

It's definitely better than the userspace signal handler (20x vs 100x). Also compared to reading one of the clock_gettime() clocks when current_clocksource is 'hpet', it's about twice as fast. So that's at least in the realm of being usable.

Since faulting would still make the vDSO clocks go through this path we'd have to be careful that whatever offsets we throw into this path don't affect the correctness of the other clocks.

[-- Attachment #1.2: tsc-test.patch --]
[-- Type: application/octet-stream, Size: 1291 bytes --]

diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index d317dc3d06a3..a6072c4e0a97 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -645,6 +645,36 @@ static bool fixup_iopl_exception(struct pt_regs *regs)
return true;
}

+static bool fixup_rdtsc_exception(struct pt_regs *regs)
+{
+ unsigned int bytes;
+ unsigned long ip;
+ u32 eax, ecx, edx;
+
+ if (insn_get_effective_ip(regs, &ip))
+ return false;
+
+ if (get_user(bytes, (const int __user *)ip))
+ return false;
+
+ if ((bytes & 0xFFFF) == 0x310f) {
+ asm volatile ("rdtsc" : "=a" (eax), "=d" (edx) ::);
+ regs->ax = eax;
+ regs->dx = edx;
+ regs->ip += 2;
+ return true;
+ } else if ((bytes & 0xFFFFFF) == 0xf9010f) {
+ asm volatile ("rdtscp" : "=a" (eax), "=d" (edx), "=c" (ecx)::);
+ regs->ax = eax;
+ regs->cx = ecx;
+ regs->dx = edx;
+ regs->ip += 3;
+ return true;
+ }
+
+ return false;
+}
+
/*
* The unprivileged ENQCMD instruction generates #GPs if the
* IA32_PASID MSR has not been populated. If possible, populate
@@ -752,6 +782,9 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
if (fixup_iopl_exception(regs))
goto exit;

+ if (fixup_rdtsc_exception(regs))
+ goto exit;
+
if (fixup_vdso_exception(regs, X86_TRAP_GP, error_code, 0))
goto exit;

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]