@@ -96,31 +96,36 @@ pub fn has_cpuid() -> bool {
96
96
let result: u32 ;
97
97
let _temp: u32 ;
98
98
asm ! ( r#"
99
- # Read eflags into $0 and copy into $1:
99
+ # Read eflags into $0 and copy it into $1:
100
100
pushfd
101
101
pop $0
102
102
mov $1, $0
103
- # Flip 21st bit:
103
+ # Flip 21st bit of $0.
104
104
xor $0, 0x200000
105
- # Set eflags:
105
+ # Set eflags to the value of $0
106
+ #
107
+ # Bit 21st can only be modified if cpuid is available
106
108
push $0
107
- popfd
108
- # Read eflags again, if cpuid is available
109
- # the 21st bit will be flipped, otherwise it
110
- # it will have the same value as the original in $1:
111
- pushfd
109
+ popfd # A
110
+ # Read eflags into $0:
111
+ pushfd # B
112
112
pop $0
113
- # Xor'ing with the original eflags should have the
114
- # 21st bit set to true if cpuid is available and zero
115
- # otherwise. All other bits have not been modified and
116
- # are zero:
113
+ # xor with the original eflags sets the bits that
114
+ # have been modified:
117
115
xor $0, $1
116
+ # There is a race between popfd (A) and pushfd (B)
117
+ # where other bits beyond 21st may have been modified due to
118
+ # interrupts, a debugger stepping through the asm, etc.
119
+ #
120
+ # Therefore, explicitly check whether the 21st bit
121
+ # was modified or not:
122
+ and $0, 0x200000
118
123
"#
119
124
: "=r" ( result) , "=r" ( _temp)
120
125
:
121
126
: "cc" , "memory"
122
127
: "intel" ) ;
123
- // Therefore, if result is 0, the bit was not modified and cpuid is
128
+ // If result == 0, the 21st bit was not modified and cpuid is
124
129
// not available. If cpuid is available, the bit was modified and
125
130
// result != 0.
126
131
result != 0
0 commit comments