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