-
Notifications
You must be signed in to change notification settings - Fork 309
[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
| 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
retland 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
retlfor 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
cpuidandxgetbyintrinsics into its own functions and exposes them as part of thex86andx86_64architectures.The
cpuidintrinsic is not available on allx86CPUs, so this also exposes ahas_cpuid() -> boolintrinsic that detect this on nonx86_64hosts, and thepushfdandpopfdintrinsics required to implement it (GCC exposes all of this as intrinsics as well).When doing run-time feature detection for
x86/x86_64we now check whether thecpuidinstruction is available, and if not, then just "disable" all features.One TODO:
xgetbvintrinsic requires thexsavetarget feature but this is not currently exposed by rustc, see Make thexsavetarget feature available on x86 in rust nightly #167 .__readeflagsis equivalent to GCC's__readeflagsexposed in/i386/ia32intrin.hand Clang's__readeflagsexposed inia32intrin.h__writeeflagsis equivalent to GCC's__writeeflagsexposed in/i386/ia32intrin.hand Clang's__writeeflagsexposed inia32intrin.h_xgetbvis equivalent to GCC's_xgetbvexposed ini386/xsaveintrin.hand Clangs'_xgetbvexposed inintrin.h_cpuid_countis equivalent to GCC's__cpuid_countexposed ini386/cpuid.hand Clang's__cpuid_countexposed incpuid.h