1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Netscape Portable Runtime (NSPR).
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1999-2000
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 :
39 : #include "primpl.h"
40 :
41 : #include <string.h>
42 : #include <unistd.h>
43 : #include <errno.h>
44 : #include <sys/time.h>
45 :
46 :
47 : #if defined(SOLARIS)
48 :
49 : static size_t
50 : GetHighResClock(void *buf, size_t maxbytes)
51 : {
52 : hrtime_t t;
53 : t = gethrtime();
54 : if (t) {
55 : return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
56 : }
57 : return 0;
58 : }
59 :
60 : #elif defined(SUNOS4)
61 :
62 : static size_t
63 : GetHighResClock(void *buf, size_t maxbytes)
64 : {
65 : return 0;
66 : }
67 :
68 : #elif defined(HPUX)
69 :
70 : #ifdef __ia64
71 : #include <ia64/sys/inline.h>
72 :
73 : static size_t
74 : GetHighResClock(void *buf, size_t maxbytes)
75 : {
76 : PRUint64 t;
77 :
78 : #ifdef __GNUC__
79 : __asm__ __volatile__("mov %0 = ar.itc" : "=r" (t));
80 : #else
81 : t = _Asm_mov_from_ar(_AREG44);
82 : #endif
83 : return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
84 : }
85 : #else
86 : static size_t
87 : GetHighResClock(void *buf, size_t maxbytes)
88 : {
89 : extern int ret_cr16();
90 : int cr16val;
91 :
92 : cr16val = ret_cr16();
93 : return(_pr_CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val)));
94 : }
95 : #endif
96 :
97 : #elif defined(OSF1)
98 :
99 : #include <c_asm.h>
100 :
101 : /*
102 : * Use the "get the cycle counter" instruction on the alpha.
103 : * The low 32 bits completely turn over in less than a minute.
104 : * The high 32 bits are some non-counter gunk that changes sometimes.
105 : */
106 : static size_t
107 : GetHighResClock(void *buf, size_t maxbytes)
108 : {
109 : unsigned long t;
110 :
111 : #ifdef __GNUC__
112 : __asm__("rpcc %0" : "=r" (t));
113 : #else
114 : t = asm("rpcc %v0");
115 : #endif
116 : return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
117 : }
118 :
119 : #elif defined(AIX)
120 :
121 : static size_t
122 : GetHighResClock(void *buf, size_t maxbytes)
123 : {
124 : return 0;
125 : }
126 :
127 : #elif (defined(LINUX) || defined(FREEBSD) || defined(__FreeBSD_kernel__) \
128 : || defined(NETBSD) || defined(__NetBSD_kernel__) || defined(OPENBSD) \
129 : || defined(SYMBIAN))
130 : #include <sys/types.h>
131 : #include <sys/stat.h>
132 : #include <fcntl.h>
133 :
134 : static int fdDevURandom;
135 : static PRCallOnceType coOpenDevURandom;
136 :
137 1404 : static PRStatus OpenDevURandom( void )
138 : {
139 1404 : fdDevURandom = open( "/dev/urandom", O_RDONLY );
140 1404 : return((-1 == fdDevURandom)? PR_FAILURE : PR_SUCCESS );
141 : } /* end OpenDevURandom() */
142 :
143 1404 : static size_t GetDevURandom( void *buf, size_t size )
144 : {
145 : int bytesIn;
146 : int rc;
147 :
148 1404 : rc = PR_CallOnce( &coOpenDevURandom, OpenDevURandom );
149 1404 : if ( PR_FAILURE == rc ) {
150 0 : _PR_MD_MAP_OPEN_ERROR( errno );
151 0 : return(0);
152 : }
153 :
154 1404 : bytesIn = read( fdDevURandom, buf, size );
155 1404 : if ( -1 == bytesIn ) {
156 0 : _PR_MD_MAP_READ_ERROR( errno );
157 0 : return(0);
158 : }
159 :
160 1404 : return( bytesIn );
161 : } /* end GetDevURandom() */
162 :
163 : static size_t
164 1404 : GetHighResClock(void *buf, size_t maxbytes)
165 : {
166 1404 : return(GetDevURandom( buf, maxbytes ));
167 : }
168 :
169 : #elif defined(NCR)
170 :
171 : static size_t
172 : GetHighResClock(void *buf, size_t maxbytes)
173 : {
174 : return 0;
175 : }
176 :
177 : #elif defined(IRIX)
178 : #include <fcntl.h>
179 : #undef PRIVATE
180 : #include <sys/mman.h>
181 : #include <sys/syssgi.h>
182 : #include <sys/immu.h>
183 : #include <sys/systeminfo.h>
184 : #include <sys/utsname.h>
185 :
186 : static size_t GetHighResClock(void *buf, size_t maxbuf)
187 : {
188 : unsigned phys_addr, raddr, cycleval;
189 : static volatile unsigned *iotimer_addr = NULL;
190 : static int tries = 0;
191 : static int cntr_size;
192 : int mfd;
193 : unsigned s0[2];
194 :
195 : #ifndef SGI_CYCLECNTR_SIZE
196 : #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */
197 : #endif
198 :
199 : if (iotimer_addr == NULL) {
200 : if (tries++ > 1) {
201 : /* Don't keep trying if it didn't work */
202 : return 0;
203 : }
204 :
205 : /*
206 : ** For SGI machines we can use the cycle counter, if it has one,
207 : ** to generate some truly random numbers
208 : */
209 : phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
210 : if (phys_addr) {
211 : int pgsz = getpagesize();
212 : int pgoffmask = pgsz - 1;
213 :
214 : raddr = phys_addr & ~pgoffmask;
215 : mfd = open("/dev/mmem", O_RDONLY);
216 : if (mfd < 0) {
217 : return 0;
218 : }
219 : iotimer_addr = (unsigned *)
220 : mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
221 : if (iotimer_addr == (unsigned*)-1) {
222 : close(mfd);
223 : iotimer_addr = NULL;
224 : return 0;
225 : }
226 : iotimer_addr = (unsigned*)
227 : ((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
228 : /*
229 : * The file 'mfd' is purposefully not closed.
230 : */
231 : cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
232 : if (cntr_size < 0) {
233 : struct utsname utsinfo;
234 :
235 : /*
236 : * We must be executing on a 6.0 or earlier system, since the
237 : * SGI_CYCLECNTR_SIZE call is not supported.
238 : *
239 : * The only pre-6.1 platforms with 64-bit counters are
240 : * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
241 : */
242 : uname(&utsinfo);
243 : if (!strncmp(utsinfo.machine, "IP19", 4) ||
244 : !strncmp(utsinfo.machine, "IP21", 4))
245 : cntr_size = 64;
246 : else
247 : cntr_size = 32;
248 : }
249 : cntr_size /= 8; /* Convert from bits to bytes */
250 : }
251 : }
252 :
253 : s0[0] = *iotimer_addr;
254 : if (cntr_size > 4)
255 : s0[1] = *(iotimer_addr + 1);
256 : memcpy(buf, (char *)&s0[0], cntr_size);
257 : return _pr_CopyLowBits(buf, maxbuf, &s0, cntr_size);
258 : }
259 :
260 : #elif defined(SONY)
261 :
262 : static size_t
263 : GetHighResClock(void *buf, size_t maxbytes)
264 : {
265 : return 0;
266 : }
267 :
268 : #elif defined(SNI)
269 : #include <sys/times.h>
270 :
271 : static size_t
272 : GetHighResClock(void *buf, size_t maxbytes)
273 : {
274 : int ticks;
275 : struct tms buffer;
276 :
277 : ticks=times(&buffer);
278 : return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
279 : }
280 :
281 : #elif defined(NEC)
282 :
283 : static size_t
284 : GetHighResClock(void *buf, size_t maxbytes)
285 : {
286 : return 0;
287 : }
288 : #elif defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(NTO) \
289 : || defined(QNX) || defined(DARWIN) || defined(RISCOS)
290 : #include <sys/times.h>
291 :
292 : static size_t
293 : GetHighResClock(void *buf, size_t maxbytes)
294 : {
295 : int ticks;
296 : struct tms buffer;
297 :
298 : ticks=times(&buffer);
299 : return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
300 : }
301 : #else
302 : #error! Platform undefined
303 : #endif /* defined(SOLARIS) */
304 :
305 1404 : extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size )
306 : {
307 : struct timeval tv;
308 1404 : int n = 0;
309 : int s;
310 :
311 1404 : n += GetHighResClock(buf, size);
312 1404 : size -= n;
313 :
314 1404 : GETTIMEOFDAY(&tv);
315 :
316 1404 : if ( size > 0 ) {
317 0 : s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec));
318 0 : size -= s;
319 0 : n += s;
320 : }
321 1404 : if ( size > 0 ) {
322 0 : s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec));
323 0 : size -= s;
324 0 : n += s;
325 : }
326 :
327 1404 : return n;
328 : } /* end _PR_MD_GetRandomNoise() */
|