-
Notifications
You must be signed in to change notification settings - Fork 287
[x86] expose cpuid, xgetbv, pushfd, popfd #166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
276cd3e
to
980f50c
Compare
Presence of |
@petrochenkov do you have an example of how that is done, or a link to some relevant material? I would then make cpuid unsafe and update the docs about how to check it (maybe offering a simpler way to check it). I'll check it out tomorrow and try to see what can be done about it. |
(I wish I didn't leave that comment, 80486 is very old.) |
@petrochenkov don't worry, I am on it. I have added a |
So this is mostly fixed. For some reason, |
bae1b96
to
dd69d94
Compare
To distinguish between i586 and i686 you should check for |
9d60edc
to
9bc28f6
Compare
src/x86/misc.rs
Outdated
let eflags_after: u32 = pushfd(); | ||
|
||
// Check if the ID bit changed: | ||
eflags_after != eflags |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gnzlbg
Have you checked what exact instruction sequence is produced?
OSDev wiki warns: "Note: Implementing this routine in for example C can lead to issues, because the compiler may change EFLAGS at any time."
(Any intermediate arithmetic operations can change EFLAGS
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I have, and the build should be green now :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It produces this in release:
has_cpuid:
pushfl
popl %eax
movl %eax, %ecx
orl $2097152, %ecx
pushl %ecx
popfl
pushfl
popl %ecx
cmpl %eax, %ecx
setne %al
retl
and this in debug:
has_cpuid:
subl $12, %esp
pushfl
popl %eax
movl %eax, 4(%esp)
movl 4(%esp), %eax
movl %eax, %ecx
orl $2097152, %ecx
pushl %ecx
popfl
pushfl
popl %ecx
movl %ecx, 8(%esp)
cmpl %eax, 8(%esp)
setne %dl
movb %dl, 3(%esp)
movb 3(%esp), %al
andb $1, %al
movzbl %al, %eax
addl $12, %esp
retl
for i686
; not "perfect" but good enough, plus I got to factor pushfd
and popf
out :)
So @alexcrichton @petrochenkov this is finished and green. The only thing that worries me is that Please review this with care since I am an inline assembly noob. |
8732131
to
73938f2
Compare
src/x86/misc.rs
Outdated
#[cfg(target_arch = "x86")] | ||
#[inline(always)] | ||
pub unsafe fn popfd(eflags: u32) { | ||
asm!("pushl $0; popfd" : : "r"(eflags) : "cc", "flags" : "volatile"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I am not 100% sure if the cc
clobber is required here.
@BurntSushi general design question: I've put these intrinsics in a The only other idea I've had is to name the modules .../ EDIT: I've opened #169 so that we don't have to block deciding on this to merge this. We can always fix this later. |
Are these listed in Intel's list of intrinsics? Or are there otherwise known canonical names for these? |
|
I could rename Note that the signature of |
09b358c
to
e935a62
Compare
Expose the `__cpuid` and `_xgetby` `x86`/`x86_64` intrinsics. The `__cpuid` and `__cpuid_count` intrinsics are not available on all `x86` CPUs. The `has_cpuid() -> bool` intrinsic detect this on non `x86_64` hosts. For convenience, this is exposed on `x86_64` as well but there it always returns `true`. These are exposed by Clang and GCC. The `__readeflags` and `__writeeflags` intrinsics, which read/write the `EFLAGS` register and are required to implement `has_cpuid`, are exposed as well. GCC and Clang exposes them too. When doing run-time feature detection for `x86`/`x86_64` we now properly check whether the `cpuid` instruction is available before using it. If it is not available, are features are exposes as "not available". One TODO: - The `_xgetbv` intrinsic requires the `xsave` target feature but this is not currently exposed by rustc, see rust-lang#167 .
@alexcrichton I've refactor this to agree naming-wise with GCC and Clang. The main difference remains that the |
Expose the `__cpuid` and `_xgetby` `x86`/`x86_64` intrinsics. The `__cpuid` and `__cpuid_count` intrinsics are not available on all `x86` CPUs. The `has_cpuid() -> bool` intrinsic detect this on non `x86_64` hosts. For convenience, this is exposed on `x86_64` as well but there it always returns `true`. These are exposed by Clang and GCC. The `__readeflags` and `__writeeflags` intrinsics, which read/write the `EFLAGS` register and are required to implement `has_cpuid`, are exposed as well. GCC and Clang exposes them too. When doing run-time feature detection for `x86`/`x86_64` we now properly check whether the `cpuid` instruction is available before using it. If it is not available, are features are exposes as "not available". One TODO: - The `_xgetbv` intrinsic requires the `xsave` target feature but this is not currently exposed by rustc, see rust-lang#167 .
Blocked by rust-lang/rust#45761 . I'll reopen this PR once that is merged upstream and I can properly use the |
This refactors the
cpuid
andxgetby
intrinsics into its own functions and exposes them as part of thex86
andx86_64
architectures.The
cpuid
intrinsic is not available on allx86
CPUs, so this also exposes ahas_cpuid() -> bool
intrinsic that detect this on nonx86_64
hosts, and thepushfd
andpopfd
intrinsics required to implement it (GCC exposes all of this as intrinsics as well).When doing run-time feature detection for
x86
/x86_64
we now check whether thecpuid
instruction is available, and if not, then just "disable" all features.One TODO:
xgetbv
intrinsic requires thexsave
target feature but this is not currently exposed by rustc, see Make thexsave
target feature available on x86 in rust nightly #167 .__readeflags
is equivalent to GCC's__readeflags
exposed in/i386/ia32intrin.h
and Clang's__readeflags
exposed inia32intrin.h
__writeeflags
is equivalent to GCC's__writeeflags
exposed in/i386/ia32intrin.h
and Clang's__writeeflags
exposed inia32intrin.h
_xgetbv
is equivalent to GCC's_xgetbv
exposed ini386/xsaveintrin.h
and Clangs'_xgetbv
exposed inintrin.h
_cpuid_count
is equivalent to GCC's__cpuid_count
exposed ini386/cpuid.h
and Clang's__cpuid_count
exposed incpuid.h