|
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 static PRStatus OpenDevURandom( void ) |
|
98 { |
|
99 fdDevURandom = open( "/dev/urandom", O_RDONLY ); |
|
100 return((-1 == fdDevURandom)? PR_FAILURE : PR_SUCCESS ); |
|
101 } /* end OpenDevURandom() */ |
|
102 |
|
103 static size_t GetDevURandom( void *buf, size_t size ) |
|
104 { |
|
105 int bytesIn; |
|
106 int rc; |
|
107 |
|
108 rc = PR_CallOnce( &coOpenDevURandom, OpenDevURandom ); |
|
109 if ( PR_FAILURE == rc ) { |
|
110 _PR_MD_MAP_OPEN_ERROR( errno ); |
|
111 return(0); |
|
112 } |
|
113 |
|
114 bytesIn = read( fdDevURandom, buf, size ); |
|
115 if ( -1 == bytesIn ) { |
|
116 _PR_MD_MAP_READ_ERROR( errno ); |
|
117 return(0); |
|
118 } |
|
119 |
|
120 return( bytesIn ); |
|
121 } /* end GetDevURandom() */ |
|
122 |
|
123 static size_t |
|
124 GetHighResClock(void *buf, size_t maxbytes) |
|
125 { |
|
126 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 extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ) |
|
230 { |
|
231 struct timeval tv; |
|
232 int n = 0; |
|
233 int s; |
|
234 |
|
235 n += GetHighResClock(buf, size); |
|
236 size -= n; |
|
237 |
|
238 GETTIMEOFDAY(&tv); |
|
239 |
|
240 if ( size > 0 ) { |
|
241 s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec)); |
|
242 size -= s; |
|
243 n += s; |
|
244 } |
|
245 if ( size > 0 ) { |
|
246 s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec)); |
|
247 size -= s; |
|
248 n += s; |
|
249 } |
|
250 |
|
251 return n; |
|
252 } /* end _PR_MD_GetRandomNoise() */ |