1 // Copyright (c) 2024 The Decred developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
4 //
5 // Feature detection originally written by Dave Collins Feb 2019.
6 7 //go:build !purego
8 9 #include "textflag.h"
10 11 // func supportsCPUID() bool
12 TEXT ·supportsCPUID(SB), $8-4
13 // Per the Intel 64 and IA-32 Architectures Software Developer's Manual,
14 // CPUID is supported if bit 21 of the EFLAGS register can be modified.
15 //
16 // To that end, this works as follows:
17 //
18 // 1. Get the current value of EFLAGS by pushing it and popping it into AX.
19 // 2. Make a copy into BX for later comparison.
20 // 3. Toggle bit 21 (the EFLAGS ID bit) of AX.
21 // 4. Put the modified value back into EFLAGS by pushing it and popping it
22 // into EFLAGS. The CPU will either update bit 21 of the EFLAGS with the
23 // modified value when it supports CPUID or leave it unmodified when it
24 // does not.
25 // 5. Get the potentially modified value of EFLAGS by pushing it and popping
26 // it into AX.
27 // 6. Compare the original and potentially modified value (aka AX vs BX)
28 // 7. CPUID is supported when they do not match since bit 21 was able to be
29 // modified.
30 PUSHFQ
31 POPQ AX
32 MOVQ AX, BX
33 XORQ $0x200000, AX
34 PUSHQ AX
35 POPFQ
36 PUSHFQ
37 POPQ AX
38 CMPQ AX, BX
39 JE nocpuid
40 MOVB $1, ret+0(FP)
41 RET
42 nocpuid:
43 MOVB $0, ret+0(FP)
44 RET
45 46 // func cpuid(eaxIn, ecxIn uint32) (eax, ebx, ecx, edx uint32)
47 TEXT ·cpuid(SB), NOSPLIT, $0-24
48 MOVL eaxIn+0(FP), AX
49 MOVL ecxIn+4(FP), CX
50 CPUID
51 MOVL AX, eax+8(FP)
52 MOVL BX, ebx+12(FP)
53 MOVL CX, ecx+16(FP)
54 MOVL DX, edx+20(FP)
55 RET
56 57 // func xgetbv() (eax uint32)
58 TEXT ·xgetbv(SB), NOSPLIT, $0-4
59 MOVL $0, CX
60 XGETBV
61 MOVL AX, eax+0(FP)
62 RET
63