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