| /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| /* ***** BEGIN LICENSE BLOCK ***** |
| * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
| * |
| * The contents of this file are subject to the Mozilla Public License Version |
| * 1.1 (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * http://www.mozilla.org/MPL/ |
| * |
| * Software distributed under the License is distributed on an "AS IS" basis, |
| * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
| * for the specific language governing rights and limitations under the |
| * License. |
| * |
| * The Original Code is the Netscape Portable Runtime (NSPR). |
| * |
| * The Initial Developer of the Original Code is |
| * Netscape Communications Corporation. |
| * Portions created by the Initial Developer are Copyright (C) 1999-2000 |
| * the Initial Developer. All Rights Reserved. |
| * |
| * Contributor(s): |
| * |
| * Alternatively, the contents of this file may be used under the terms of |
| * either the GNU General Public License Version 2 or later (the "GPL"), or |
| * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
| * in which case the provisions of the GPL or the LGPL are applicable instead |
| * of those above. If you wish to allow use of your version of this file only |
| * under the terms of either the GPL or the LGPL, and not to allow others to |
| * use your version of this file under the terms of the MPL, indicate your |
| * decision by deleting the provisions above and replace them with the notice |
| * and other provisions required by the GPL or the LGPL. If you do not delete |
| * the provisions above, a recipient may use your version of this file under |
| * the terms of any one of the MPL, the GPL or the LGPL. |
| * |
| * ***** END LICENSE BLOCK ***** */ |
| |
| |
| #include "primpl.h" |
| |
| #include <string.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <sys/time.h> |
| |
| |
| #if defined(SOLARIS) |
| |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| hrtime_t t; |
| t = gethrtime(); |
| if (t) { |
| return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); |
| } |
| return 0; |
| } |
| |
| #elif defined(SUNOS4) |
| |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| return 0; |
| } |
| |
| #elif defined(HPUX) |
| |
| #ifdef __ia64 |
| #include <ia64/sys/inline.h> |
| |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| PRUint64 t; |
| |
| #ifdef __GNUC__ |
| __asm__ __volatile__("mov %0 = ar.itc" : "=r" (t)); |
| #else |
| t = _Asm_mov_from_ar(_AREG44); |
| #endif |
| return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); |
| } |
| #else |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| extern int ret_cr16(); |
| int cr16val; |
| |
| cr16val = ret_cr16(); |
| return(_pr_CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val))); |
| } |
| #endif |
| |
| #elif defined(OSF1) |
| |
| #include <c_asm.h> |
| |
| /* |
| * Use the "get the cycle counter" instruction on the alpha. |
| * The low 32 bits completely turn over in less than a minute. |
| * The high 32 bits are some non-counter gunk that changes sometimes. |
| */ |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| unsigned long t; |
| |
| #ifdef __GNUC__ |
| __asm__("rpcc %0" : "=r" (t)); |
| #else |
| t = asm("rpcc %v0"); |
| #endif |
| return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); |
| } |
| |
| #elif defined(AIX) |
| |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| return 0; |
| } |
| |
| #elif (defined(LINUX) || defined(FREEBSD) || defined(__FreeBSD_kernel__) \ |
| || defined(NETBSD) || defined(__NetBSD_kernel__) || defined(OPENBSD) \ |
| || defined(SYMBIAN)) |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| |
| static int fdDevURandom; |
| static PRCallOnceType coOpenDevURandom; |
| |
| static PRStatus OpenDevURandom( void ) |
| { |
| fdDevURandom = open( "/dev/urandom", O_RDONLY ); |
| return((-1 == fdDevURandom)? PR_FAILURE : PR_SUCCESS ); |
| } /* end OpenDevURandom() */ |
| |
| static size_t GetDevURandom( void *buf, size_t size ) |
| { |
| int bytesIn; |
| int rc; |
| |
| rc = PR_CallOnce( &coOpenDevURandom, OpenDevURandom ); |
| if ( PR_FAILURE == rc ) { |
| _PR_MD_MAP_OPEN_ERROR( errno ); |
| return(0); |
| } |
| |
| bytesIn = read( fdDevURandom, buf, size ); |
| if ( -1 == bytesIn ) { |
| _PR_MD_MAP_READ_ERROR( errno ); |
| return(0); |
| } |
| |
| return( bytesIn ); |
| } /* end GetDevURandom() */ |
| |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| return(GetDevURandom( buf, maxbytes )); |
| } |
| |
| #elif defined(NCR) |
| |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| return 0; |
| } |
| |
| #elif defined(IRIX) |
| #include <fcntl.h> |
| #undef PRIVATE |
| #include <sys/mman.h> |
| #include <sys/syssgi.h> |
| #include <sys/immu.h> |
| #include <sys/systeminfo.h> |
| #include <sys/utsname.h> |
| |
| static size_t GetHighResClock(void *buf, size_t maxbuf) |
| { |
| unsigned phys_addr, raddr, cycleval; |
| static volatile unsigned *iotimer_addr = NULL; |
| static int tries = 0; |
| static int cntr_size; |
| int mfd; |
| unsigned s0[2]; |
| |
| #ifndef SGI_CYCLECNTR_SIZE |
| #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ |
| #endif |
| |
| if (iotimer_addr == NULL) { |
| if (tries++ > 1) { |
| /* Don't keep trying if it didn't work */ |
| return 0; |
| } |
| |
| /* |
| ** For SGI machines we can use the cycle counter, if it has one, |
| ** to generate some truly random numbers |
| */ |
| phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); |
| if (phys_addr) { |
| int pgsz = getpagesize(); |
| int pgoffmask = pgsz - 1; |
| |
| raddr = phys_addr & ~pgoffmask; |
| mfd = open("/dev/mmem", O_RDONLY); |
| if (mfd < 0) { |
| return 0; |
| } |
| iotimer_addr = (unsigned *) |
| mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr); |
| if (iotimer_addr == (unsigned*)-1) { |
| close(mfd); |
| iotimer_addr = NULL; |
| return 0; |
| } |
| iotimer_addr = (unsigned*) |
| ((__psint_t)iotimer_addr | (phys_addr & pgoffmask)); |
| /* |
| * The file 'mfd' is purposefully not closed. |
| */ |
| cntr_size = syssgi(SGI_CYCLECNTR_SIZE); |
| if (cntr_size < 0) { |
| struct utsname utsinfo; |
| |
| /* |
| * We must be executing on a 6.0 or earlier system, since the |
| * SGI_CYCLECNTR_SIZE call is not supported. |
| * |
| * The only pre-6.1 platforms with 64-bit counters are |
| * IP19 and IP21 (Challenge, PowerChallenge, Onyx). |
| */ |
| uname(&utsinfo); |
| if (!strncmp(utsinfo.machine, "IP19", 4) || |
| !strncmp(utsinfo.machine, "IP21", 4)) |
| cntr_size = 64; |
| else |
| cntr_size = 32; |
| } |
| cntr_size /= 8; /* Convert from bits to bytes */ |
| } |
| } |
| |
| s0[0] = *iotimer_addr; |
| if (cntr_size > 4) |
| s0[1] = *(iotimer_addr + 1); |
| memcpy(buf, (char *)&s0[0], cntr_size); |
| return _pr_CopyLowBits(buf, maxbuf, &s0, cntr_size); |
| } |
| |
| #elif defined(SONY) |
| |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| return 0; |
| } |
| |
| #elif defined(SNI) |
| #include <sys/times.h> |
| |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| int ticks; |
| struct tms buffer; |
| |
| ticks=times(&buffer); |
| return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); |
| } |
| |
| #elif defined(NEC) |
| |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| return 0; |
| } |
| #elif defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(NTO) \ |
| || defined(QNX) || defined(DARWIN) || defined(RISCOS) |
| #include <sys/times.h> |
| |
| static size_t |
| GetHighResClock(void *buf, size_t maxbytes) |
| { |
| int ticks; |
| struct tms buffer; |
| |
| ticks=times(&buffer); |
| return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); |
| } |
| #else |
| #error! Platform undefined |
| #endif /* defined(SOLARIS) */ |
| |
| extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ) |
| { |
| struct timeval tv; |
| int n = 0; |
| int s; |
| |
| n += GetHighResClock(buf, size); |
| size -= n; |
| |
| GETTIMEOFDAY(&tv); |
| |
| if ( size > 0 ) { |
| s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec)); |
| size -= s; |
| n += s; |
| } |
| if ( size > 0 ) { |
| s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec)); |
| size -= s; |
| n += s; |
| } |
| |
| return n; |
| } /* end _PR_MD_GetRandomNoise() */ |