physseed64.asm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. %include "defs.asm"
  2. ;************************* physseed64.asm **********************************
  3. ; Author: Agner Fog
  4. ; Date created: 2010-08-03
  5. ; Last modified: 2013-09-13
  6. ; Source URL: www.agner.org/optimize
  7. ; Project: asmlib.zip
  8. ; C++ prototype:
  9. ; extern "C" int PhysicalSeed(int seeds[], int NumSeeds);
  10. ;
  11. ; Description:
  12. ; Generates a non-deterministic random seed from a physical random number generator
  13. ; which is available on some processors.
  14. ; Uses the time stamp counter (which is less random) if no physical random number
  15. ; generator is available.
  16. ; The code is not optimized for speed because it is typically called only once.
  17. ;
  18. ; Parameters:
  19. ; int seeds[] An array which will be filled with random numbers
  20. ; int NumSeeds Indicates the desired number of 32-bit random numbers
  21. ;
  22. ; Return value: 0 Failure. No suitable instruction available (processor older than Pentium)
  23. ; 1 No physical random number generator. Used time stamp counter instead
  24. ; 2 Success. VIA physical random number generator used
  25. ; 3 Success. Intel physical random number generator used
  26. ; 4 Success. Intel physical seed generator used
  27. ;
  28. ; The return value will indicate the availability of a physical random number generator
  29. ; even if NumSeeds = 0.
  30. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  31. default rel
  32. %define NUM_TRIES 20 ; max number of tries for rdseed and rdrand instructions
  33. %define TESTING 0 ; 1 for test only
  34. global PhysicalSeed
  35. ; Direct entries to CPU-specific versions
  36. global PhysicalSeedNone: function
  37. global PhysicalSeedRDTSC: function
  38. global PhysicalSeedVIA: function
  39. global PhysicalSeedRDRand: function
  40. global PhysicalSeedRDSeed function
  41. ; ***************************************************************************
  42. ; Define registers used for function parameters, used in 64-bit mode only
  43. ; ***************************************************************************
  44. %IFDEF WINDOWS
  45. %define par1 rcx
  46. %define par2 rdx
  47. %define par3 r8
  48. %define par1d ecx
  49. %define par2d edx
  50. %define par3d r8d
  51. %ENDIF
  52. %IFDEF UNIX
  53. %define par1 rdi
  54. %define par2 rsi
  55. %define par3 rdx
  56. %define par1d edi
  57. %define par2d esi
  58. %define par3d edx
  59. %ENDIF
  60. SECTION .text align=16
  61. %IFDEF WINDOWS
  62. global PhysicalSeedD@8 ; DLL version
  63. PhysicalSeedD@8:
  64. %ENDIF
  65. PhysicalSeed:
  66. jmp [PhysicalSeedDispatch] ; Go to appropriate version, depending on instructions available
  67. PhysicalSeedRDSeed:
  68. push rbx
  69. test par2d, par2d ; NumSeeds
  70. jz S300
  71. js S900
  72. mov par3d, par2d ; NumSeeds
  73. shr par3d, 1
  74. jz S150
  75. ; do 64 bits at a time
  76. S100: mov ebx, NUM_TRIES
  77. S110: ; rdseed rax
  78. %if TESTING
  79. mov eax, par3d
  80. stc
  81. %ELSE
  82. db 48h, 0Fh, 0C7h, 0F8h ; rdseed rax
  83. %ENDIF
  84. jc S120
  85. ; failed. try again
  86. dec ebx
  87. jz S900
  88. jmp S110
  89. S120: mov [par1], rax
  90. add par1, 8
  91. dec par3d
  92. jnz S100 ; loop 64 bits
  93. S150:
  94. and par2d, 1
  95. jz S300
  96. ; an odd 32 bit remains
  97. S200: mov ebx, NUM_TRIES
  98. S210: ; rdseed rax
  99. %if TESTING
  100. mov eax, par3d
  101. stc
  102. %ELSE
  103. db 0Fh, 0C7h, 0F8h ; rdseed eax
  104. %ENDIF
  105. jc S220
  106. ; failed. try again
  107. dec ebx
  108. jz S900
  109. jmp S210
  110. S220: mov [par1], eax
  111. S300: mov eax, 4 ; return value
  112. pop rbx
  113. ret
  114. S900: ; failure
  115. xor eax, eax ; return 0
  116. pop rbx
  117. ret
  118. PhysicalSeedRDRand:
  119. push rbx
  120. test par2d, par2d ; NumSeeds
  121. jz R300
  122. js R900
  123. mov par3d, par2d ; NumSeeds
  124. shr par3d, 1 ; NumSeeds/2
  125. jz R150
  126. ; do 64 bits at a time
  127. R100: mov ebx, NUM_TRIES
  128. R110: ; rdrand rax
  129. %if TESTING
  130. mov eax, par3d
  131. stc
  132. %ELSE
  133. db 48h, 0Fh, 0C7h, 0F0h ; rdrand rax
  134. %ENDIF
  135. jc R120
  136. ; failed. try again
  137. dec ebx
  138. jz R900
  139. jmp R110
  140. R120: mov [par1], rax
  141. add par1, 8
  142. dec par3d
  143. jnz R100 ; loop 64 bits
  144. R150:
  145. and par2d, 1
  146. jz R300
  147. ; an odd 32 bit remains
  148. R200: mov ebx, NUM_TRIES
  149. R210: ; rdrand eax
  150. %if TESTING
  151. mov eax, par3d
  152. stc
  153. %ELSE
  154. db 0Fh, 0C7h, 0F0h ; rdrand eax
  155. %ENDIF
  156. jc R220
  157. ; failed. try again
  158. dec ebx
  159. jz R900
  160. jmp R210
  161. R220: mov [par1], eax
  162. R300: mov eax, 4 ; return value
  163. pop rbx
  164. ret
  165. R900: ; failure
  166. xor eax, eax ; return 0
  167. pop rbx
  168. ret
  169. PhysicalSeedVIA:
  170. ; VIA XSTORE supported
  171. push rbx
  172. %IFDEF WINDOWS
  173. push rsi
  174. push rdi
  175. mov rdi, rcx ; seeds
  176. mov esi, edx ; NumSeeds
  177. %ENDIF
  178. mov ecx, esi ; NumSeeds
  179. and ecx, -2 ; round down to nearest even
  180. jz T200 ; NumSeeds <= 1
  181. ; make an even number of random dwords
  182. shl ecx, 2 ; number of bytes (divisible by 8)
  183. mov edx, 3 ; quality factor
  184. %if TESTING
  185. mov eax, 1
  186. rep stosb
  187. %ELSE
  188. db 0F3H, 00FH, 0A7H, 0C0H ; rep xstore instuction
  189. %ENDIF
  190. T200:
  191. test esi, 1
  192. jz T300
  193. ; NumSeeds is odd. Make 8 bytes in temporary buffer and store 4 of the bytes
  194. mov rbx, rdi ; current output pointer
  195. mov ecx, 4 ; Will generate 4 or 8 bytes, depending on CPU
  196. mov edx, 3 ; quality factor
  197. push rcx ; make temporary space on stack
  198. mov rdi, rsp ; point to buffer on stack
  199. %if TESTING
  200. mov eax, 1
  201. rep stosb
  202. %ELSE
  203. db 0F3H, 00FH, 0A7H, 0C0H ; rep xstore instuction
  204. %ENDIF
  205. pop rax
  206. mov [rbx], eax ; store the last 4 bytes
  207. T300:
  208. mov eax, 2 ; return value
  209. %IFDEF WINDOWS
  210. pop rdi
  211. pop rsi
  212. %ENDIF
  213. pop rbx
  214. ret
  215. PhysicalSeedRDTSC:
  216. %IFDEF WINDOWS
  217. push rbx
  218. push rcx
  219. push rdx
  220. xor eax, eax
  221. cpuid ; serialize
  222. rdtsc ; get time stamp counter
  223. pop rbx ; numseeds
  224. pop rcx ; seeds
  225. test ebx, ebx
  226. jz U300 ; zero seeds
  227. js U900 ; failure
  228. mov [rcx], eax ; store time stamp counter as seeds[0]
  229. add rcx, 4
  230. dec ebx
  231. jz U300
  232. mov [rcx], edx ; store upper part of time stamp counter as seeds[1]
  233. add rcx, 4
  234. dec ebx
  235. jz U300
  236. xor eax, eax
  237. U100: mov [rcx], eax ; store 0 for the rest
  238. add rcx, 4
  239. dec ebx
  240. jnz U100
  241. U300: mov eax, 1 ; return value
  242. pop rbx
  243. ret
  244. U900: ; failure
  245. xor eax, eax ; return 0
  246. pop rbx
  247. ret
  248. %ELSE ; UNIX
  249. push rbx
  250. xor eax, eax
  251. cpuid ; serialize
  252. rdtsc ; get time stamp counter
  253. test esi, esi ; numseeds
  254. jz U300 ; zero seeds
  255. js U900 ; failure
  256. mov [rdi], eax ; store time stamp counter as seeds[0]
  257. add rdi, 4
  258. dec esi
  259. jz U300
  260. mov [rdi], edx ; store upper part of time stamp counter as seeds[1]
  261. add rdi, 4
  262. dec esi
  263. jz U300
  264. xor eax, eax
  265. U100: mov [rdi], eax ; store 0 for the rest
  266. add rdi, 4
  267. dec esi
  268. jnz U100
  269. U300: mov eax, 1 ; return value
  270. pop rbx
  271. ret
  272. U900: ; failure
  273. xor eax, eax ; return 0
  274. pop rbx
  275. ret
  276. %ENDIF
  277. PhysicalSeedNone: ; no possible generation
  278. xor eax, eax
  279. test par2d, par2d ; numseeds
  280. jz N200
  281. N100: mov [par1], eax
  282. add par1, 4
  283. dec par2d
  284. jnz N100
  285. N200: ret ; return 0
  286. PhysicalSeedDispatcher:
  287. push rbx
  288. %IFDEF WINDOWS
  289. push rcx
  290. push rdx
  291. %ENDIF
  292. ; test if RDSEED supported
  293. xor eax, eax
  294. cpuid
  295. cmp eax, 7
  296. jb P200 ; RDSEED not supported
  297. mov eax, 7
  298. xor ecx, ecx
  299. cpuid
  300. bt ebx, 18
  301. ; jc USE_RDSEED ; not tested yet!!
  302. P200: ; test if RDRAND supported
  303. mov eax, 1
  304. cpuid
  305. bt ecx, 30
  306. jc USE_RDRAND
  307. ; test if VIA xstore instruction supported
  308. mov eax, 0C0000000H
  309. push rax
  310. cpuid
  311. pop rbx
  312. cmp eax, ebx
  313. jna P300 ; not a VIA processor
  314. lea eax, [rbx+1]
  315. cpuid
  316. bt edx, 3
  317. jc VIA_METHOD
  318. P300: ; test if RDTSC supported
  319. mov eax, 1
  320. cpuid
  321. bt edx, 4
  322. jc USE_RDTSC ; XSTORE instruction not supported or not enabled
  323. FAILURE: ; No useful instruction supported
  324. lea rax, [PhysicalSeedNone]
  325. jmp P800
  326. USE_RDRAND: ; Use RDRAND instruction
  327. lea rax, [PhysicalSeedRDRand]
  328. jmp P800
  329. USE_RDSEED: ; Use RDSEED instruction (not tested yet)
  330. lea rax, [PhysicalSeedRDSeed]
  331. jmp P800
  332. VIA_METHOD: ; Use VIA xstore instructions
  333. lea rax, [PhysicalSeedVIA]
  334. jmp P800
  335. USE_RDTSC:
  336. lea rax, [PhysicalSeedRDTSC]
  337. ;jmp P800
  338. P800: mov [PhysicalSeedDispatch], rax
  339. %IFDEF WINDOWS
  340. pop rdx
  341. pop rcx
  342. %ENDIF
  343. pop rbx
  344. jmp rax ; continue in dispatched version
  345. ; -----------------------------------------------------------------
  346. ; Data section for dispatcher
  347. ; -----------------------------------------------------------------
  348. SECTION .data
  349. ; Pointer to appropriate versions. Initially point to dispatcher
  350. PhysicalSeedDispatch DQ PhysicalSeedDispatcher
  351. %IFDEF POSITIONINDEPENDENT
  352. ; Fix potential problem in Mac linker
  353. DD 0, 0
  354. %ENDIF