Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 :
7 : #include "primpl.h"
8 :
9 : #include <string.h>
10 : #include <unistd.h>
11 : #include <errno.h>
12 : #include <sys/time.h>
13 :
14 :
15 : #if defined(SOLARIS)
16 :
17 : static size_t
18 : GetHighResClock(void *buf, size_t maxbytes)
19 : {
20 : hrtime_t t;
21 : t = gethrtime();
22 : if (t) {
23 : return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
24 : }
25 : return 0;
26 : }
27 :
28 : #elif defined(HPUX)
29 :
30 : #ifdef __ia64
31 : #include <ia64/sys/inline.h>
32 :
33 : static size_t
34 : GetHighResClock(void *buf, size_t maxbytes)
35 : {
36 : PRUint64 t;
37 :
38 : #ifdef __GNUC__
39 : __asm__ __volatile__("mov %0 = ar.itc" : "=r" (t));
40 : #else
41 : t = _Asm_mov_from_ar(_AREG44);
42 : #endif
43 : return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
44 : }
45 : #else
46 : static size_t
47 : GetHighResClock(void *buf, size_t maxbytes)
48 : {
49 : extern int ret_cr16();
50 : int cr16val;
51 :
52 : cr16val = ret_cr16();
53 : return(_pr_CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val)));
54 : }
55 : #endif
56 :
57 : #elif defined(OSF1)
58 :
59 : #include <c_asm.h>
60 :
61 : /*
62 : * Use the "get the cycle counter" instruction on the alpha.
63 : * The low 32 bits completely turn over in less than a minute.
64 : * The high 32 bits are some non-counter gunk that changes sometimes.
65 : */
66 : static size_t
67 : GetHighResClock(void *buf, size_t maxbytes)
68 : {
69 : unsigned long t;
70 :
71 : #ifdef __GNUC__
72 : __asm__("rpcc %0" : "=r" (t));
73 : #else
74 : t = asm("rpcc %v0");
75 : #endif
76 : return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
77 : }
78 :
79 : #elif defined(AIX)
80 :
81 : static size_t
82 : GetHighResClock(void *buf, size_t maxbytes)
83 : {
84 : return 0;
85 : }
86 :
87 : #elif (defined(LINUX) || defined(FREEBSD) || defined(__FreeBSD_kernel__) \
88 : || defined(NETBSD) || defined(__NetBSD_kernel__) || defined(OPENBSD) \
89 : || defined(SYMBIAN) || defined(__GNU__))
90 : #include <sys/types.h>
91 : #include <sys/stat.h>
92 : #include <fcntl.h>
93 :
94 : static int fdDevURandom;
95 : static PRCallOnceType coOpenDevURandom;
96 :
97 3 : static PRStatus OpenDevURandom( void )
98 : {
99 3 : fdDevURandom = open( "/dev/urandom", O_RDONLY );
100 3 : return((-1 == fdDevURandom)? PR_FAILURE : PR_SUCCESS );
101 : } /* end OpenDevURandom() */
102 :
103 3 : static size_t GetDevURandom( void *buf, size_t size )
104 : {
105 : int bytesIn;
106 : int rc;
107 :
108 3 : rc = PR_CallOnce( &coOpenDevURandom, OpenDevURandom );
109 3 : if ( PR_FAILURE == rc ) {
110 0 : _PR_MD_MAP_OPEN_ERROR( errno );
111 0 : return(0);
112 : }
113 :
114 3 : bytesIn = read( fdDevURandom, buf, size );
115 3 : if ( -1 == bytesIn ) {
116 0 : _PR_MD_MAP_READ_ERROR( errno );
117 0 : return(0);
118 : }
119 :
120 3 : return( bytesIn );
121 : } /* end GetDevURandom() */
122 :
123 : static size_t
124 3 : GetHighResClock(void *buf, size_t maxbytes)
125 : {
126 3 : return(GetDevURandom( buf, maxbytes ));
127 : }
128 :
129 : #elif defined(IRIX)
130 : #include <fcntl.h>
131 : #undef PRIVATE
132 : #include <sys/mman.h>
133 : #include <sys/syssgi.h>
134 : #include <sys/immu.h>
135 : #include <sys/systeminfo.h>
136 : #include <sys/utsname.h>
137 :
138 : static size_t GetHighResClock(void *buf, size_t maxbuf)
139 : {
140 : unsigned phys_addr, raddr, cycleval;
141 : static volatile unsigned *iotimer_addr = NULL;
142 : static int tries = 0;
143 : static int cntr_size;
144 : int mfd;
145 : unsigned s0[2];
146 :
147 : #ifndef SGI_CYCLECNTR_SIZE
148 : #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */
149 : #endif
150 :
151 : if (iotimer_addr == NULL) {
152 : if (tries++ > 1) {
153 : /* Don't keep trying if it didn't work */
154 : return 0;
155 : }
156 :
157 : /*
158 : ** For SGI machines we can use the cycle counter, if it has one,
159 : ** to generate some truly random numbers
160 : */
161 : phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
162 : if (phys_addr) {
163 : int pgsz = getpagesize();
164 : int pgoffmask = pgsz - 1;
165 :
166 : raddr = phys_addr & ~pgoffmask;
167 : mfd = open("/dev/mmem", O_RDONLY);
168 : if (mfd < 0) {
169 : return 0;
170 : }
171 : iotimer_addr = (unsigned *)
172 : mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
173 : if (iotimer_addr == (unsigned*)-1) {
174 : close(mfd);
175 : iotimer_addr = NULL;
176 : return 0;
177 : }
178 : iotimer_addr = (unsigned*)
179 : ((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
180 : /*
181 : * The file 'mfd' is purposefully not closed.
182 : */
183 : cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
184 : if (cntr_size < 0) {
185 : struct utsname utsinfo;
186 :
187 : /*
188 : * We must be executing on a 6.0 or earlier system, since the
189 : * SGI_CYCLECNTR_SIZE call is not supported.
190 : *
191 : * The only pre-6.1 platforms with 64-bit counters are
192 : * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
193 : */
194 : uname(&utsinfo);
195 : if (!strncmp(utsinfo.machine, "IP19", 4) ||
196 : !strncmp(utsinfo.machine, "IP21", 4))
197 : cntr_size = 64;
198 : else
199 : cntr_size = 32;
200 : }
201 : cntr_size /= 8; /* Convert from bits to bytes */
202 : }
203 : }
204 :
205 : s0[0] = *iotimer_addr;
206 : if (cntr_size > 4)
207 : s0[1] = *(iotimer_addr + 1);
208 : memcpy(buf, (char *)&s0[0], cntr_size);
209 : return _pr_CopyLowBits(buf, maxbuf, &s0, cntr_size);
210 : }
211 :
212 : #elif defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(NTO) \
213 : || defined(QNX) || defined(DARWIN) || defined(RISCOS)
214 : #include <sys/times.h>
215 :
216 : static size_t
217 : GetHighResClock(void *buf, size_t maxbytes)
218 : {
219 : int ticks;
220 : struct tms buffer;
221 :
222 : ticks=times(&buffer);
223 : return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
224 : }
225 : #else
226 : #error! Platform undefined
227 : #endif /* defined(SOLARIS) */
228 :
229 3 : extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size )
230 : {
231 : struct timeval tv;
232 3 : int n = 0;
233 : int s;
234 :
235 3 : n += GetHighResClock(buf, size);
236 3 : size -= n;
237 :
238 3 : GETTIMEOFDAY(&tv);
239 :
240 3 : if ( size > 0 ) {
241 0 : s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec));
242 0 : size -= s;
243 0 : n += s;
244 : }
245 3 : if ( size > 0 ) {
246 0 : s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec));
247 0 : size -= s;
248 0 : n += s;
249 : }
250 :
251 3 : return n;
252 : } /* end _PR_MD_GetRandomNoise() */
|