1;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
2;;              Copyright assigned to the Crypto++ project.
3
4;; This ASM file provides RDSEED to downlevel Microsoft tool chains.
5;; Everything "just works" under Visual Studio. Other platforms will
6;; have to run MASM/MASM-64 and then link to the object files.
7
8;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
9;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
10;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\ml.exe" %ASFLAGS% /Fo rdrand-x86.obj /c rdrand.asm
11;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64\ml64.exe" %ASFLAGS64% /Fo rdrand-x64.obj /c rdrand.asm
12
13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
15
16TITLE    MASM_RDSEED_GenerateBlock source file
17SUBTITLE Microsoft specific ASM code to utilize RDSEED for down level Microsoft toolchains
18
19PUBLIC MASM_RDSEED_GenerateBlock
20
21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23
24;; C/C++ Function prototypes (both are fastcall)
25;;   X86:
26;;      extern "C" void __fastcall MASM_RDSEED_GenerateBlock(byte* ptr, size_t size);
27;;   X64:
28;;      extern "C" void __fastcall MASM_RDSEED_GenerateBlock(byte* ptr, size_t size);
29
30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
32
33IFDEF _M_X86    ;; Set via the command line
34
35.486
36.MODEL FLAT
37
38;; Fastcall calling conventions exports
39ALIAS <@MASM_RDSEED_GenerateBlock@8> = <MASM_RDSEED_GenerateBlock>
40
41ENDIF
42
43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45
46IFDEF _M_X86    ;; Set via the command line
47
48.CODE
49ALIGN   8
50OPTION PROLOGUE:NONE
51OPTION EPILOGUE:NONE
52
53;; No need for Load_Arguments due to fastcall
54;;   ECX (in): arg1, byte* buffer
55;;   EDX (in): arg2, size_t bsize
56
57MASM_RDSEED_GenerateBlock PROC   ;; arg1:DWORD, arg2:DWORD
58
59    MWSIZE EQU 04h    ;; machine word size
60    buffer EQU ecx
61    bsize  EQU edx
62
63            ;; Top of While loop
64RDSEED_GenerateBlock_Top:
65
66            ;; Check remaining size
67    cmp     bsize, 0
68    je      RDSEED_GenerateBlock_Return
69
70RDSEED_Call_EAX:
71            ;; RDSEED is not available prior to VS2012. Just emit
72            ;;   the byte codes using DB. This is `rdseed eax`.
73    DB      0Fh, 0C7h, 0F8h
74
75            ;; If CF=1, the number returned by RDSEED is valid.
76            ;; If CF=0, a random number was not available.
77
78            ;; Retry immediately
79    jnc     RDSEED_Call_EAX
80
81RDSEED_succeeded:
82
83    cmp     bsize, MWSIZE
84    jb      RDSEED_Partial_Machine_Word
85
86RDSEED_Full_Machine_Word:
87
88    mov     DWORD PTR [buffer], eax
89    add     buffer, MWSIZE        ;; No need for Intel Core 2 slow workarounds, like
90    sub     bsize, MWSIZE         ;;   `lea buffer,[buffer+MWSIZE]` for faster adds
91
92            ;; Continue
93    jmp     RDSEED_GenerateBlock_Top
94
95            ;; 1,2,3 bytes remain
96RDSEED_Partial_Machine_Word:
97
98            ;; Test bit 1 to see if size is at least 2
99    test    bsize, 2
100    jz      RDSEED_Bit_1_Not_Set
101
102    mov     WORD PTR [buffer], ax
103    shr     eax, 16
104    add     buffer, 2
105
106RDSEED_Bit_1_Not_Set:
107
108            ;; Test bit 0 to see if size is at least 1
109    test    bsize, 1
110    jz      RDSEED_Bit_0_Not_Set
111
112    mov     BYTE PTR [buffer], al
113    ;; shr     ax, 8
114    ;; add     buffer, 1
115
116RDSEED_Bit_0_Not_Set:
117
118            ;; We've hit all the bits
119
120RDSEED_GenerateBlock_Return:
121
122            ;; Clear artifacts
123    xor     eax, eax
124    ret
125
126MASM_RDSEED_GenerateBlock ENDP
127
128ENDIF    ;; _M_X86
129
130;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
131;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
132
133IFDEF _M_X64    ;; Set via the command line
134
135.CODE
136ALIGN   16
137OPTION PROLOGUE:NONE
138OPTION EPILOGUE:NONE
139
140;; No need for Load_Arguments due to fastcall
141;;   RCX (in): arg1, byte* buffer
142;;   RDX (in): arg2, size_t bsize
143
144MASM_RDSEED_GenerateBlock PROC   ;; arg1:QWORD, arg2:QWORD
145
146    MWSIZE EQU 08h    ;; machine word size
147    buffer EQU rcx
148    bsize  EQU rdx
149
150            ;; Top of While loop
151RDSEED_GenerateBlock_Top:
152
153            ;; Check remaining size
154    cmp     bsize, 0
155    je      RDSEED_GenerateBlock_Return
156
157RDSEED_Call_RAX:
158            ;; RDSEED is not available prior to VS2012. Just emit
159            ;;   the byte codes using DB. This is `rdseed rax`.
160    DB      048h, 0Fh, 0C7h, 0F8h
161
162            ;; If CF=1, the number returned by RDSEED is valid.
163            ;; If CF=0, a random number was not available.
164
165            ;; Retry immediately
166    jnc     RDSEED_Call_RAX
167
168RDSEED_succeeded:
169
170    cmp     bsize, MWSIZE
171    jb      RDSEED_Partial_Machine_Word
172
173RDSEED_Full_Machine_Word:
174
175    mov     QWORD PTR [buffer], rax
176    add     buffer, MWSIZE
177    sub     bsize, MWSIZE
178
179            ;; Continue
180    jmp     RDSEED_GenerateBlock_Top
181
182            ;; 1,2,3,4,5,6,7 bytes remain
183RDSEED_Partial_Machine_Word:
184
185            ;; Test bit 2 to see if size is at least 4
186    test    bsize, 4
187    jz      RDSEED_Bit_2_Not_Set
188
189    mov     DWORD PTR [buffer], eax
190    shr     rax, 32
191    add     buffer, 4
192
193RDSEED_Bit_2_Not_Set:
194
195            ;; Test bit 1 to see if size is at least 2
196    test    bsize, 2
197    jz      RDSEED_Bit_1_Not_Set
198
199    mov     WORD PTR [buffer], ax
200    shr     eax, 16
201    add     buffer, 2
202
203RDSEED_Bit_1_Not_Set:
204
205            ;; Test bit 0 to see if size is at least 1
206    test    bsize, 1
207    jz      RDSEED_Bit_0_Not_Set
208
209    mov     BYTE PTR [buffer], al
210    ;; shr     ax, 8
211    ;; add     buffer, 1
212
213RDSEED_Bit_0_Not_Set:
214
215            ;; We've hit all the bits
216
217RDSEED_GenerateBlock_Return:
218
219            ;; Clear artifacts
220    xor     rax, rax
221    ret
222
223MASM_RDSEED_GenerateBlock ENDP
224
225ENDIF    ;; _M_X64
226
227;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
228;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
229
230END
231