chiark / gitweb /
base/dispatch-x86ish.S (dispatch_x86ish_cpuid): Add missing `#undef'.
[catacomb] / base / dispatch-x86ish.S
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
40 FUNC(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
49         mov     edi, [SP + 12]
50         mov     eax, [SP + 16]
51         mov     ecx, [SP + 20]
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
70         // dance with the flags register.  This is unnecessary on AMD64,
71         // which postdates the introduction of `cpuid'.
72 #if CPUFAM_X86
73         pushf
74         pop     DX                      // current flags in d
75
76         or      DX, EFLAGS_ID           // force the id bit on and check it
77         push    DX
78         popf
79         pushf
80         pop     DX
81         test    edx, EFLAGS_ID
82         jz      8f
83
84         and     DX, ~EFLAGS_ID          // force the id bit off and check it
85         push    DX
86         popf
87         pushf
88         pop     DX
89         test    edx, EFLAGS_ID
90         jnz     8f
91 #endif
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.
103 9:
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.
114 #if CPUFAM_X86
115 8:      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
122 #endif
123
124 #undef OUT
125 ENDFUNC
126
127 ///--------------------------------------------------------------------------
128 /// Probing for XMM register availability.
129
130 FUNC(dispatch_x86ish_xmmregisters_p)
131         // Enter with no arguments.  Return nonzero if the XMM registers are
132         // usable.
133
134         pushreg BP
135         setfp
136         stalloc 512
137         and     SP, ~15
138   endprologue
139
140         // Save the floating point and SIMD registers, and try to clobber
141         // xmm0.
142         lea     DX, [SP + 160]
143         fxsave  [SP]
144         mov     eax, [DX]
145         xor     dword ptr [DX], 0xaaaa5555
146         fxrstor [SP]
147
148         // Save them again, and read back the low word of xmm0.  Undo the
149         // clobbering and restore.
150         fxsave  [SP]
151         mov     ecx, [DX]
152         mov     [DX], eax
153         fxrstor [SP]
154
155         // The register are live if we read different things.
156         xor     eax, ecx
157
158         // Done.
159         dropfp
160         popreg  BP
161         ret
162 ENDFUNC
163
164 ///--------------------------------------------------------------------------
165 /// Checking extended control registers.
166
167 FUNC(dispatch_x86ish_xgetbv)
168         // Call with two arguments: a pointer Z_OUT to 8 bytes of output space, and
169         // a 32-bit integer C.  Read the 64-bit value of XCR(C), and store it
170         // at Z_OUT.
171
172 #if CPUFAM_X86
173 #  define Z_OUT edi
174         pushreg edi
175         mov     edi, [esp + 8]
176         mov     ecx, [esp + 12]
177 #endif
178 #if CPUFAM_AMD64 && ABI_SYSV
179 #  define Z_OUT rdi
180         mov     ecx, esi
181 #endif
182 #if CPUFAM_AMD64 && ABI_WIN
183 #  define Z_OUT r8
184         mov     r8, rcx
185         mov     ecx, edx
186 #endif
187   endprologue
188
189         xgetbv
190         mov     [Z_OUT + 0], eax
191         mov     [Z_OUT + 4], edx
192
193 #if CPUFAM_X86
194         popreg  edi
195 #endif
196         ret
197
198 #undef Z_OUT
199 ENDFUNC
200
201 ///--------------------------------------------------------------------------
202 /// Checking `rdrand'.
203
204 FUNC(dispatch_x86ish_rdrand)
205         // Enter with two arguments: a code OP requesting either `rdrand' (0)
206         // or `rdseed' (1), and a pointer X_OUT to a 32-bit word.  Try to
207         // generate a random word using the requested instruction'.  If
208         // successful, set *X_OUT to the generated word, and return zero;
209         // otherwise, return -1.
210
211 #if CPUFAM_X86
212 #  define OP eax
213 #  define X_OUT edx
214 #  define COUNT ecx
215         mov     OP, [SP + 4]
216         mov     X_OUT, [SP + 8]
217 #endif
218 #if CPUFAM_AMD64 && ABI_SYSV
219 #  define OP edi
220 #  define X_OUT rsi
221 #  define COUNT ecx
222 #endif
223 #if CPUFAM_AMD64 && ABI_WIN
224 #  define OP rcx
225 #  define X_OUT rdx
226 #  define COUNT r8d
227 #endif
228   endprologue
229
230         cmp     OP, 0
231         mov     COUNT, 16               // fairly persistent
232         jne     1f
233
234 0:      rdrand  eax
235         jc      9f
236         dec     COUNT
237         jnz     0b
238         jmp     8f
239
240 1:      rdseed  eax
241         jc      9f
242         dec     COUNT
243         jnz     1b
244         jmp     8f
245
246         // Failed to come up with a random value.
247 8:      mov     eax, -1
248         ret
249
250         // Success.
251 9:      mov     [X_OUT], eax
252         xor     eax, eax
253         ret
254
255 #undef X_OUT
256 #undef COUNT
257
258 ENDFUNC
259
260 ///----- That's all, folks --------------------------------------------------