chiark / gitweb /
base/dispatch.c, base/dispatch-x86ish.S: Add opcode to `rdrand_works_p'.
[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.
71         pushf
72         pop     DX                      // current flags in d
73
74         or      DX, EFLAGS_ID           // force the id bit on and check it
75         push    DX
76         popf
77         pushf
78         pop     DX
79         test    edx, EFLAGS_ID
80         jz      8f
81
82         and     DX, ~EFLAGS_ID          // force the id bit off and check it
83         push    DX
84         popf
85         pushf
86         pop     DX
87         test    edx, EFLAGS_ID
88         jnz     8f
89
90         // OK, that seemed to work.
91         cpuid
92
93         mov     [OUT + 0], eax
94         mov     [OUT + 4], ebx
95         mov     [OUT + 8], ecx
96         mov     [OUT + 12], edx
97         xor     eax, eax
98
99         // We're done.
100 9:
101 #if CPUFAM_X86
102         popreg  edi
103         popreg  ebx
104 #endif
105 #if CPUFAM_AMD64
106         popreg  rbx
107 #endif
108         ret
109
110         // Failed.
111 8:      xor     eax, eax
112         mov     [OUT + 0], eax
113         mov     [OUT + 4], eax
114         mov     [OUT + 8], eax
115         mov     [OUT + 12], eax
116         mov     eax, -1
117         jmp     9b
118 ENDFUNC
119
120 ///--------------------------------------------------------------------------
121 /// Probing for XMM register availability.
122
123 FUNC(dispatch_x86ish_xmmregisters_p)
124         // Enter with no arguments.  Return nonzero if the XMM registers are
125         // usable.
126
127         pushreg BP
128         setfp
129         stalloc 512
130         and     SP, ~15
131   endprologue
132
133         // Save the floating point and SIMD registers, and try to clobber
134         // xmm0.
135         lea     DX, [SP + 160]
136         fxsave  [SP]
137         mov     eax, [DX]
138         xor     dword ptr [DX], 0xaaaa5555
139         fxrstor [SP]
140
141         // Save them again, and read back the low word of xmm0.  Undo the
142         // clobbering and restore.
143         fxsave  [SP]
144         mov     ecx, [DX]
145         mov     [DX], eax
146         fxrstor [SP]
147
148         // The register are live if we read different things.
149         xor     eax, ecx
150
151         // Done.
152         dropfp
153         popreg  BP
154         ret
155 ENDFUNC
156
157 ///--------------------------------------------------------------------------
158 /// Checking `rdrand'.
159
160 FUNC(dispatch_x86ish_rdrand)
161         // Enter with two arguments: a code OP requesting `rdrand' (0), and a
162         // pointer X_OUT to a 32-bit word.  Try to generate a random word
163         // using the requested instruction.  If successful, set *X_OUT to the
164         // generated word, and return zero; otherwise, return -1.
165
166 #if CPUFAM_X86
167 #  define OP eax
168 #  define X_OUT edx
169 #  define COUNT ecx
170         mov     OP, [SP + 4]
171         mov     X_OUT, [SP + 8]
172 #endif
173 #if CPUFAM_AMD64 && ABI_SYSV
174 #  define OP edi
175 #  define X_OUT rsi
176 #  define COUNT ecx
177 #endif
178 #if CPUFAM_AMD64 && ABI_WIN
179 #  define OP rcx
180 #  define X_OUT rdx
181 #  define COUNT r8d
182 #endif
183   endprologue
184
185         mov     COUNT, 16               // fairly persistent
186 0:      rdrand  eax
187         jc      9f
188         dec     COUNT
189         jnz     0b
190         jmp     8f
191
192         // Failed to come up with a random value.
193 8:      mov     eax, -1
194         ret
195
196         // Success.
197 9:      mov     [X_OUT], eax
198         xor     eax, eax
199         ret
200
201 #undef X_OUT
202 #undef COUNT
203
204 ENDFUNC
205
206 ///----- That's all, folks --------------------------------------------------