summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2012-01-17 07:30:36 +0000
committerkib <kib@FreeBSD.org>2012-01-17 07:30:36 +0000
commit6a34de7c5a0e59d6349ce628792e19d793eeb2b4 (patch)
treee5c90bbb0de4037c03826cbe27748513837da981 /sys/amd64
parente94bd75cc576b894958cd5eedcf1d25919af0fd4 (diff)
downloadFreeBSD-src-6a34de7c5a0e59d6349ce628792e19d793eeb2b4.zip
FreeBSD-src-6a34de7c5a0e59d6349ce628792e19d793eeb2b4.tar.gz
Implement xsetbv(), xsave() and xrstor() providing C access to the
similarly named CPU instructions. Since our in-tree binutils gas is not aware of the instructions, and I have to use the byte-sequence to encode them, hardcode the r/m operand as (%rdi). This way, first argument of the pseudo-function is already placed into proper register. MFC after: 1 week
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/include/cpufunc.h38
1 files changed, 38 insertions, 0 deletions
diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h
index c07e09b..9b147c7 100644
--- a/sys/amd64/include/cpufunc.h
+++ b/sys/amd64/include/cpufunc.h
@@ -669,6 +669,41 @@ intr_restore(register_t rflags)
write_rflags(rflags);
}
+static __inline void
+xsetbv(uint32_t reg, uint64_t val)
+{
+ uint32_t low, hi;
+
+ low = val;
+ hi = val >> 32;
+ __asm __volatile(".byte 0x0f,0x01,0xd1" : :
+ "c" (reg), "a" (low), "d" (hi));
+}
+
+static __inline void
+xsave(char *addr, uint64_t mask)
+{
+ uint32_t low, hi;
+
+ low = mask;
+ hi = mask >> 32;
+ /* xsave (%rdi) */
+ __asm __volatile(".byte 0x0f,0xae,0x27" : :
+ "a" (low), "d" (hi), "D" (addr) : "memory");
+}
+
+static __inline void
+xrstor(char *addr, uint64_t mask)
+{
+ uint32_t low, hi;
+
+ low = mask;
+ hi = mask >> 32;
+ /* xrstor (%rdi) */
+ __asm __volatile(".byte 0x0f,0xae,0x2f" : :
+ "a" (low), "d" (hi), "D" (addr));
+}
+
#else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
int breakpoint(void);
@@ -733,6 +768,9 @@ u_int rgs(void);
void wbinvd(void);
void write_rflags(u_int rf);
void wrmsr(u_int msr, uint64_t newval);
+void xsetbv(uint32_t reg, uint64_t val);
+void xsave(char *addr, uint64_t mask);
+void xrstor(char *addr, uint64_t mask);
#endif /* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */
OpenPOWER on IntegriCloud