diff options
author | kib <kib@FreeBSD.org> | 2012-01-17 07:30:36 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2012-01-17 07:30:36 +0000 |
commit | 6a34de7c5a0e59d6349ce628792e19d793eeb2b4 (patch) | |
tree | e5c90bbb0de4037c03826cbe27748513837da981 /sys/amd64 | |
parent | e94bd75cc576b894958cd5eedcf1d25919af0fd4 (diff) | |
download | FreeBSD-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.h | 38 |
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 */ |