Upload Tizen:Base source
[toolchains/nspr.git] / mozilla / nsprpub / pr / src / md / unix / uxrng.c
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 \f
60 #elif defined(SUNOS4)
61
62 static size_t
63 GetHighResClock(void *buf, size_t maxbytes)
64 {
65     return 0;
66 }
67 \f
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 \f
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 \f
119 #elif defined(AIX)
120
121 static size_t
122 GetHighResClock(void *buf, size_t maxbytes)
123 {
124     return 0;
125 }
126 \f
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 static PRStatus OpenDevURandom( void )
138 {
139     fdDevURandom = open( "/dev/urandom", O_RDONLY );
140     return((-1 == fdDevURandom)? PR_FAILURE : PR_SUCCESS );
141 } /* end OpenDevURandom() */
142
143 static size_t GetDevURandom( void *buf, size_t size )
144 {
145     int bytesIn;
146     int rc;
147
148     rc = PR_CallOnce( &coOpenDevURandom, OpenDevURandom );
149     if ( PR_FAILURE == rc ) {
150         _PR_MD_MAP_OPEN_ERROR( errno );
151         return(0);
152     }
153
154     bytesIn = read( fdDevURandom, buf, size );
155     if ( -1 == bytesIn ) {
156         _PR_MD_MAP_READ_ERROR( errno );
157         return(0);
158     }
159
160     return( bytesIn );
161 } /* end GetDevURandom() */
162
163 static size_t
164 GetHighResClock(void *buf, size_t maxbytes)
165 {             
166     return(GetDevURandom( buf, maxbytes ));
167 }
168 \f
169 #elif defined(NCR)
170
171 static size_t
172 GetHighResClock(void *buf, size_t maxbytes)
173 {
174     return 0;
175 }
176 \f
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 \f
260 #elif defined(SONY)
261
262 static size_t
263 GetHighResClock(void *buf, size_t maxbytes)
264 {
265     return 0;
266 }
267 \f
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 \f
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 \f
305 extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size )
306 {
307     struct timeval tv;
308     int n = 0;
309     int s;
310
311     n += GetHighResClock(buf, size);
312     size -= n;
313
314     GETTIMEOFDAY(&tv);
315
316     if ( size > 0 ) {
317         s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec));
318         size -= s;
319         n += s;
320     }
321     if ( size > 0 ) {
322         s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec));
323         size -= s;
324         n += s;
325     }
326
327     return n;
328 } /* end _PR_MD_GetRandomNoise() */