On Fri, Apr 02, 2021 at 10:37:36AM -0700, Mike Larkin wrote:
> On Thu, Apr 01, 2021 at 06:43:30PM -0500, Scott Cheloha wrote:
> > 
> > [...]
> > 
> > Hmmm.  Being able to work around this would be nice.
> >
> > FreeBSD has code that uses WRMSR to synchronize the TSC:
> >
> > https://cgit.freebsd.org/src/commit/sys/x86/x86/tsc.c?id=b2c63698d4b81576e0c8842263ee86e86cd34e76
> >
> > My guess is that support for writing the TSC is not implemented by
> > every hypervisor, so we would need to be very careful in deciding when
> > to try it.  Otherwise we end up with protection faults and other crap
> > we don't want.
> >
> 
> We implemented rdmsr_safe for things like this. We could probably do the same
> for wrmsr.

Like this?

Sorry if this is not idiomatic.  I don't write much assembly.

I tested this a bit on my laptop.  Stuff like:

        wrmsr_safe(MSR_TSC, rdtsc() + 100);

Which seems to desync the normally synchronized TSCs here.

Unclear what the rules are for RETGUARD.  I just copied what was in
rdmsr_safe().  We're not using R10 so we can use R10?

-Scott

Index: include/cpufunc.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/include/cpufunc.h,v
retrieving revision 1.36
diff -u -p -r1.36 cpufunc.h
--- include/cpufunc.h   13 Sep 2020 11:53:16 -0000      1.36
+++ include/cpufunc.h   4 Apr 2021 03:16:48 -0000
@@ -398,6 +398,7 @@ struct cpu_info_full;
 void cpu_enter_pages(struct cpu_info_full *);
 
 int rdmsr_safe(u_int msr, uint64_t *);
+int wrmsr_safe(uint32_t msr, uint64_t);
 
 #endif /* _KERNEL */
 
Index: amd64/locore.S
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/locore.S,v
retrieving revision 1.122
diff -u -p -r1.122 locore.S
--- amd64/locore.S      3 Nov 2020 18:19:31 -0000       1.122
+++ amd64/locore.S      4 Apr 2021 03:16:48 -0000
@@ -1154,6 +1154,30 @@ NENTRY(rdmsr_resume)
        ret
 END(rdmsr_safe)
 
+/* int wrmsr_safe(uint32_t msr, uint64_t val) */
+ENTRY(wrmsr_safe)
+       RETGUARD_SETUP(wrmsr_safe, r10)
+
+       movl    %edi,   %ecx    /* uint32_t msr */
+
+       movl    %esi,   %eax    /* uint64_t val */
+       sarq    $32,    %rsi
+       movl    %esi,   %edx
+       
+       .globl  wrmsr_safe_fault
+wrmsr_safe_fault:
+       wrmsr
+
+       xorq    %rax,   %rax
+       RETGUARD_CHECK(rdmsr_safe, r10)
+       ret
+
+NENTRY(wrmsr_resume)
+       movq    $0x1,   %rax
+       RETGUARD_CHECK(wrmsr_safe, r10)
+       ret
+END(wrmsr_safe)
+
 #if NXEN > 0
        /* Hypercall page needs to be page aligned */
        .text

Reply via email to