base/dispatch.c, base/dispatch-x86ish.S: Add opcode to `rdrand_works_p'.
[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
70 // dance with the flags register.
71 pushf
a90d420c 72 pop DX // current flags in d
a3ad4421 73
a90d420c
MW
74 or DX, EFLAGS_ID // force the id bit on and check it
75 push DX
a3ad4421
MW
76 popf
77 pushf
a90d420c 78 pop DX
a3ad4421
MW
79 test edx, EFLAGS_ID
80 jz 8f
81
a90d420c
MW
82 and DX, ~EFLAGS_ID // force the id bit off and check it
83 push DX
a3ad4421
MW
84 popf
85 pushf
a90d420c 86 pop DX
a3ad4421
MW
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.
1009:
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.
1118: 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
118ENDFUNC
119
120///--------------------------------------------------------------------------
121/// Probing for XMM register availability.
122
123FUNC(dispatch_x86ish_xmmregisters_p)
124 // Enter with no arguments. Return nonzero if the XMM registers are
125 // usable.
126
a90d420c 127 pushreg BP
a3ad4421
MW
128 setfp
129 stalloc 512
a90d420c 130 and SP, ~15
a3ad4421
MW
131 endprologue
132
133 // Save the floating point and SIMD registers, and try to clobber
134 // xmm0.
4d99c15e 135 lea DX, [SP + 160]
a90d420c 136 fxsave [SP]
4d99c15e
MW
137 mov eax, [DX]
138 xor dword ptr [DX], 0xaaaa5555
a90d420c 139 fxrstor [SP]
a3ad4421
MW
140
141 // Save them again, and read back the low word of xmm0. Undo the
142 // clobbering and restore.
a90d420c 143 fxsave [SP]
4d99c15e
MW
144 mov ecx, [DX]
145 mov [DX], eax
a90d420c 146 fxrstor [SP]
a3ad4421
MW
147
148 // The register are live if we read different things.
149 xor eax, ecx
150
151 // Done.
152 dropfp
a90d420c 153 popreg BP
a3ad4421
MW
154 ret
155ENDFUNC
156
25f3ce6a
MW
157///--------------------------------------------------------------------------
158/// Checking `rdrand'.
159
160FUNC(dispatch_x86ish_rdrand)
1b07c4f3
MW
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.
25f3ce6a
MW
165
166#if CPUFAM_X86
1b07c4f3 167# define OP eax
25f3ce6a
MW
168# define X_OUT edx
169# define COUNT ecx
1b07c4f3
MW
170 mov OP, [SP + 4]
171 mov X_OUT, [SP + 8]
25f3ce6a
MW
172#endif
173#if CPUFAM_AMD64 && ABI_SYSV
1b07c4f3
MW
174# define OP edi
175# define X_OUT rsi
25f3ce6a
MW
176# define COUNT ecx
177#endif
178#if CPUFAM_AMD64 && ABI_WIN
1b07c4f3
MW
179# define OP rcx
180# define X_OUT rdx
181# define COUNT r8d
25f3ce6a
MW
182#endif
183 endprologue
184
185 mov COUNT, 16 // fairly persistent
1860: rdrand eax
187 jc 9f
188 dec COUNT
189 jnz 0b
1b07c4f3 190 jmp 8f
25f3ce6a
MW
191
192 // Failed to come up with a random value.
1b07c4f3 1938: mov eax, -1
25f3ce6a
MW
194 ret
195
196 // Success.
1979: mov [X_OUT], eax
198 xor eax, eax
199 ret
200
201#undef X_OUT
202#undef COUNT
203
204ENDFUNC
205
a3ad4421 206///----- That's all, folks --------------------------------------------------