base/dispatch-x86ish.S (dispatch_x86ish_cpuid): Skip `EFLAGS_ID' dance on AMD64.
[catacomb] / base / dispatch-x86ish.S
CommitLineData
a3ad4421
MW
1/// -*- mode: asm; asm-comment-char: ?/ -*-
2///
3/// CPU dispatch support for x86
4///
5/// (c) 2019 Straylight/Edgeware
6///
7
8///----- Licensing notice ---------------------------------------------------
9///
10/// This file is part of Catacomb.
11///
12/// Catacomb is free software: you can redistribute it and/or modify it
13/// under the terms of the GNU Library General Public License as published
14/// by the Free Software Foundation; either version 2 of the License, or
15/// (at your option) any later version.
16///
17/// Catacomb is distributed in the hope that it will be useful, but
18/// WITHOUT ANY WARRANTY; without even the implied warranty of
19/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20/// Library General Public License for more details.
21///
22/// You should have received a copy of the GNU Library General Public
23/// License along with Catacomb. If not, write to the Free Software
24/// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25/// USA.
26
27///--------------------------------------------------------------------------
28/// Preliminaries.
29
30#include "config.h"
31#include "asm-common.h"
32
33 EFLAGS_ID = 1 << 21
34
35 .text
36
37///--------------------------------------------------------------------------
38/// Probing for CPUID.
39
40FUNC(dispatch_x86ish_cpuid)
41 // Enter with a pointer to 16 bytes of storage for the output A, B,
42 // C, D values in the first argument, and input A and C values in the
43 // second and third. Fill the output buffer with `cpuid' results and
44 // return zero if we can; otherwise fill with zero and return -1.
45
46#if CPUFAM_X86
47 pushreg ebx
48 pushreg edi
a90d420c
MW
49 mov edi, [SP + 12]
50 mov eax, [SP + 16]
51 mov ecx, [SP + 20]
a3ad4421
MW
52# define OUT edi
53#endif
54#if CPUFAM_AMD64 && ABI_SYSV
55 pushreg rbx
56 mov eax, esi
57 mov ecx, edx
58# define OUT rdi
59#endif
60#if CPUFAM_AMD64 && ABI_WIN
61 pushreg rbx
62 mov r9, rcx
63 mov eax, edx
64 mov ecx, r8d
65# define OUT r9
66#endif
67 endprologue
68
69 // First, check that this is even a thing, using the complicated
ca6a6ec7
MW
70 // dance with the flags register. This is unnecessary on AMD64,
71 // which postdates the introduction of `cpuid'.
72#if CPUFAM_X86
a3ad4421 73 pushf
a90d420c 74 pop DX // current flags in d
a3ad4421 75
a90d420c
MW
76 or DX, EFLAGS_ID // force the id bit on and check it
77 push DX
a3ad4421
MW
78 popf
79 pushf
a90d420c 80 pop DX
a3ad4421
MW
81 test edx, EFLAGS_ID
82 jz 8f
83
a90d420c
MW
84 and DX, ~EFLAGS_ID // force the id bit off and check it
85 push DX
a3ad4421
MW
86 popf
87 pushf
a90d420c 88 pop DX
a3ad4421
MW
89 test edx, EFLAGS_ID
90 jnz 8f
ca6a6ec7 91#endif
a3ad4421
MW
92
93 // OK, that seemed to work.
94 cpuid
95
96 mov [OUT + 0], eax
97 mov [OUT + 4], ebx
98 mov [OUT + 8], ecx
99 mov [OUT + 12], edx
100 xor eax, eax
101
102 // We're done.
1039:
104#if CPUFAM_X86
105 popreg edi
106 popreg ebx
107#endif
108#if CPUFAM_AMD64
109 popreg rbx
110#endif
111 ret
112
113 // Failed.
ca6a6ec7 114#if CPUFAM_X86
a3ad4421
MW
1158: xor eax, eax
116 mov [OUT + 0], eax
117 mov [OUT + 4], eax
118 mov [OUT + 8], eax
119 mov [OUT + 12], eax
120 mov eax, -1
121 jmp 9b
ca6a6ec7 122#endif
a3ad4421
MW
123ENDFUNC
124
125///--------------------------------------------------------------------------
126/// Probing for XMM register availability.
127
128FUNC(dispatch_x86ish_xmmregisters_p)
129 // Enter with no arguments. Return nonzero if the XMM registers are
130 // usable.
131
a90d420c 132 pushreg BP
a3ad4421
MW
133 setfp
134 stalloc 512
a90d420c 135 and SP, ~15
a3ad4421
MW
136 endprologue
137
138 // Save the floating point and SIMD registers, and try to clobber
139 // xmm0.
4d99c15e 140 lea DX, [SP + 160]
a90d420c 141 fxsave [SP]
4d99c15e
MW
142 mov eax, [DX]
143 xor dword ptr [DX], 0xaaaa5555
a90d420c 144 fxrstor [SP]
a3ad4421
MW
145
146 // Save them again, and read back the low word of xmm0. Undo the
147 // clobbering and restore.
a90d420c 148 fxsave [SP]
4d99c15e
MW
149 mov ecx, [DX]
150 mov [DX], eax
a90d420c 151 fxrstor [SP]
a3ad4421
MW
152
153 // The register are live if we read different things.
154 xor eax, ecx
155
156 // Done.
157 dropfp
a90d420c 158 popreg BP
a3ad4421
MW
159 ret
160ENDFUNC
161
25f3ce6a 162///--------------------------------------------------------------------------
00b52725
MW
163/// Checking extended control registers.
164
165FUNC(dispatch_x86ish_xgetbv)
166 // Call with two arguments: a pointer Z_OUT to 8 bytes of output space, and
167 // a 32-bit integer C. Read the 64-bit value of XCR(C), and store it
168 // at Z_OUT.
169
170#if CPUFAM_X86
171# define Z_OUT edi
e1ac8bd9
MW
172 pushreg edi
173 mov edi, [esp + 8]
174 mov ecx, [esp + 12]
00b52725
MW
175#endif
176#if CPUFAM_AMD64 && ABI_SYSV
177# define Z_OUT rdi
178 mov ecx, esi
179#endif
180#if CPUFAM_AMD64 && ABI_WIN
181# define Z_OUT r8
182 mov r8, rcx
183 mov ecx, edx
184#endif
185 endprologue
186
187 xgetbv
188 mov [Z_OUT + 0], eax
189 mov [Z_OUT + 4], edx
190
e1ac8bd9
MW
191#if CPUFAM_X86
192 popreg edi
193#endif
00b52725
MW
194 ret
195
196#undef Z_OUT
197ENDFUNC
198
199///--------------------------------------------------------------------------
25f3ce6a
MW
200/// Checking `rdrand'.
201
202FUNC(dispatch_x86ish_rdrand)
6c0946ef
MW
203 // Enter with two arguments: a code OP requesting either `rdrand' (0)
204 // or `rdseed' (1), and a pointer X_OUT to a 32-bit word. Try to
205 // generate a random word using the requested instruction'. If
206 // successful, set *X_OUT to the generated word, and return zero;
207 // otherwise, return -1.
25f3ce6a
MW
208
209#if CPUFAM_X86
1b07c4f3 210# define OP eax
25f3ce6a
MW
211# define X_OUT edx
212# define COUNT ecx
1b07c4f3
MW
213 mov OP, [SP + 4]
214 mov X_OUT, [SP + 8]
25f3ce6a
MW
215#endif
216#if CPUFAM_AMD64 && ABI_SYSV
1b07c4f3
MW
217# define OP edi
218# define X_OUT rsi
25f3ce6a
MW
219# define COUNT ecx
220#endif
221#if CPUFAM_AMD64 && ABI_WIN
1b07c4f3
MW
222# define OP rcx
223# define X_OUT rdx
224# define COUNT r8d
25f3ce6a
MW
225#endif
226 endprologue
227
6c0946ef 228 cmp OP, 0
25f3ce6a 229 mov COUNT, 16 // fairly persistent
6c0946ef
MW
230 jne 1f
231
25f3ce6a
MW
2320: rdrand eax
233 jc 9f
234 dec COUNT
235 jnz 0b
1b07c4f3 236 jmp 8f
25f3ce6a 237
6c0946ef
MW
2381: rdseed eax
239 jc 9f
240 dec COUNT
241 jnz 1b
242 jmp 8f
243
25f3ce6a 244 // Failed to come up with a random value.
1b07c4f3 2458: mov eax, -1
25f3ce6a
MW
246 ret
247
248 // Success.
2499: mov [X_OUT], eax
250 xor eax, eax
251 ret
252
253#undef X_OUT
254#undef COUNT
255
256ENDFUNC
257
a3ad4421 258///----- That's all, folks --------------------------------------------------