andre@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: andre@0: #include "primpl.h" andre@0: andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: andre@0: andre@0: #if defined(SOLARIS) andre@0: andre@0: static size_t andre@0: GetHighResClock(void *buf, size_t maxbytes) andre@0: { andre@0: hrtime_t t; andre@0: t = gethrtime(); andre@0: if (t) { andre@0: return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); andre@0: } andre@0: return 0; andre@0: } andre@0: andre@0: #elif defined(HPUX) andre@0: andre@0: #ifdef __ia64 andre@0: #include andre@0: andre@0: static size_t andre@0: GetHighResClock(void *buf, size_t maxbytes) andre@0: { andre@0: PRUint64 t; andre@0: andre@0: #ifdef __GNUC__ andre@0: __asm__ __volatile__("mov %0 = ar.itc" : "=r" (t)); andre@0: #else andre@0: t = _Asm_mov_from_ar(_AREG44); andre@0: #endif andre@0: return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); andre@0: } andre@0: #else andre@0: static size_t andre@0: GetHighResClock(void *buf, size_t maxbytes) andre@0: { andre@0: extern int ret_cr16(); andre@0: int cr16val; andre@0: andre@0: cr16val = ret_cr16(); andre@0: return(_pr_CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val))); andre@0: } andre@0: #endif andre@0: andre@0: #elif defined(OSF1) andre@0: andre@0: #include andre@0: andre@0: /* andre@0: * Use the "get the cycle counter" instruction on the alpha. andre@0: * The low 32 bits completely turn over in less than a minute. andre@0: * The high 32 bits are some non-counter gunk that changes sometimes. andre@0: */ andre@0: static size_t andre@0: GetHighResClock(void *buf, size_t maxbytes) andre@0: { andre@0: unsigned long t; andre@0: andre@0: #ifdef __GNUC__ andre@0: __asm__("rpcc %0" : "=r" (t)); andre@0: #else andre@0: t = asm("rpcc %v0"); andre@0: #endif andre@0: return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); andre@0: } andre@0: andre@0: #elif defined(AIX) andre@0: andre@0: static size_t andre@0: GetHighResClock(void *buf, size_t maxbytes) andre@0: { andre@0: return 0; andre@0: } andre@0: andre@0: #elif (defined(LINUX) || defined(FREEBSD) || defined(__FreeBSD_kernel__) \ andre@0: || defined(NETBSD) || defined(__NetBSD_kernel__) || defined(OPENBSD) \ andre@0: || defined(SYMBIAN) || defined(__GNU__)) andre@0: #include andre@0: #include andre@0: #include andre@0: andre@0: static int fdDevURandom; andre@0: static PRCallOnceType coOpenDevURandom; andre@0: andre@0: static PRStatus OpenDevURandom( void ) andre@0: { andre@0: fdDevURandom = open( "/dev/urandom", O_RDONLY ); andre@0: return((-1 == fdDevURandom)? PR_FAILURE : PR_SUCCESS ); andre@0: } /* end OpenDevURandom() */ andre@0: andre@0: static size_t GetDevURandom( void *buf, size_t size ) andre@0: { andre@0: int bytesIn; andre@0: int rc; andre@0: andre@0: rc = PR_CallOnce( &coOpenDevURandom, OpenDevURandom ); andre@0: if ( PR_FAILURE == rc ) { andre@0: _PR_MD_MAP_OPEN_ERROR( errno ); andre@0: return(0); andre@0: } andre@0: andre@0: bytesIn = read( fdDevURandom, buf, size ); andre@0: if ( -1 == bytesIn ) { andre@0: _PR_MD_MAP_READ_ERROR( errno ); andre@0: return(0); andre@0: } andre@0: andre@0: return( bytesIn ); andre@0: } /* end GetDevURandom() */ andre@0: andre@0: static size_t andre@0: GetHighResClock(void *buf, size_t maxbytes) andre@0: { andre@0: return(GetDevURandom( buf, maxbytes )); andre@0: } andre@0: andre@0: #elif defined(IRIX) andre@0: #include andre@0: #undef PRIVATE andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: #include andre@0: andre@0: static size_t GetHighResClock(void *buf, size_t maxbuf) andre@0: { andre@0: unsigned phys_addr, raddr, cycleval; andre@0: static volatile unsigned *iotimer_addr = NULL; andre@0: static int tries = 0; andre@0: static int cntr_size; andre@0: int mfd; andre@0: unsigned s0[2]; andre@0: andre@0: #ifndef SGI_CYCLECNTR_SIZE andre@0: #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ andre@0: #endif andre@0: andre@0: if (iotimer_addr == NULL) { andre@0: if (tries++ > 1) { andre@0: /* Don't keep trying if it didn't work */ andre@0: return 0; andre@0: } andre@0: andre@0: /* andre@0: ** For SGI machines we can use the cycle counter, if it has one, andre@0: ** to generate some truly random numbers andre@0: */ andre@0: phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); andre@0: if (phys_addr) { andre@0: int pgsz = getpagesize(); andre@0: int pgoffmask = pgsz - 1; andre@0: andre@0: raddr = phys_addr & ~pgoffmask; andre@0: mfd = open("/dev/mmem", O_RDONLY); andre@0: if (mfd < 0) { andre@0: return 0; andre@0: } andre@0: iotimer_addr = (unsigned *) andre@0: mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr); andre@0: if (iotimer_addr == (unsigned*)-1) { andre@0: close(mfd); andre@0: iotimer_addr = NULL; andre@0: return 0; andre@0: } andre@0: iotimer_addr = (unsigned*) andre@0: ((__psint_t)iotimer_addr | (phys_addr & pgoffmask)); andre@0: /* andre@0: * The file 'mfd' is purposefully not closed. andre@0: */ andre@0: cntr_size = syssgi(SGI_CYCLECNTR_SIZE); andre@0: if (cntr_size < 0) { andre@0: struct utsname utsinfo; andre@0: andre@0: /* andre@0: * We must be executing on a 6.0 or earlier system, since the andre@0: * SGI_CYCLECNTR_SIZE call is not supported. andre@0: * andre@0: * The only pre-6.1 platforms with 64-bit counters are andre@0: * IP19 and IP21 (Challenge, PowerChallenge, Onyx). andre@0: */ andre@0: uname(&utsinfo); andre@0: if (!strncmp(utsinfo.machine, "IP19", 4) || andre@0: !strncmp(utsinfo.machine, "IP21", 4)) andre@0: cntr_size = 64; andre@0: else andre@0: cntr_size = 32; andre@0: } andre@0: cntr_size /= 8; /* Convert from bits to bytes */ andre@0: } andre@0: } andre@0: andre@0: s0[0] = *iotimer_addr; andre@0: if (cntr_size > 4) andre@0: s0[1] = *(iotimer_addr + 1); andre@0: memcpy(buf, (char *)&s0[0], cntr_size); andre@0: return _pr_CopyLowBits(buf, maxbuf, &s0, cntr_size); andre@0: } andre@0: andre@0: #elif defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(NTO) \ andre@0: || defined(QNX) || defined(DARWIN) || defined(RISCOS) andre@0: #include andre@0: andre@0: static size_t andre@0: GetHighResClock(void *buf, size_t maxbytes) andre@0: { andre@0: int ticks; andre@0: struct tms buffer; andre@0: andre@0: ticks=times(&buffer); andre@0: return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); andre@0: } andre@0: #else andre@0: #error! Platform undefined andre@0: #endif /* defined(SOLARIS) */ andre@0: andre@0: extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ) andre@0: { andre@0: struct timeval tv; andre@0: int n = 0; andre@0: int s; andre@0: andre@0: n += GetHighResClock(buf, size); andre@0: size -= n; andre@0: andre@0: GETTIMEOFDAY(&tv); andre@0: andre@0: if ( size > 0 ) { andre@0: s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec)); andre@0: size -= s; andre@0: n += s; andre@0: } andre@0: if ( size > 0 ) { andre@0: s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec)); andre@0: size -= s; andre@0: n += s; andre@0: } andre@0: andre@0: return n; andre@0: } /* end _PR_MD_GetRandomNoise() */