mirror of https://github.com/openssl/openssl.git
				
				
				
			
		
			
	
	
		
			477 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			477 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | /* 
 | ||
|  | ------- Strong random data generation on a Macintosh (pre - OS X) ------ | ||
|  | 		 | ||
|  | --	GENERAL: We aim to generate unpredictable bits without explicit | ||
|  | 	user interaction. A general review of the problem may be found | ||
|  | 	in RFC 1750, "Randomness Recommendations for Security", and some | ||
|  | 	more discussion, of general and Mac-specific issues has appeared | ||
|  | 	in "Using and Creating Cryptographic- Quality Random Numbers" by | ||
|  | 	Jon Callas (www.merrymeet.com/jon/usingrandom.html). | ||
|  | 
 | ||
|  | 	The data and entropy estimates provided below are based on my | ||
|  | 	limited experimentation and estimates, rather than by any | ||
|  | 	rigorous study, and the entropy estimates tend to be optimistic. | ||
|  | 	They should not be considered absolute. | ||
|  | 
 | ||
|  | 	Some of the information being collected may be correlated in | ||
|  | 	subtle ways. That includes mouse positions, timings, and disk | ||
|  | 	size measurements. Some obvious correlations will be eliminated | ||
|  | 	by the programmer, but other, weaker ones may remain. The | ||
|  | 	reliability of the code depends on such correlations being | ||
|  | 	poorly understood, both by us and by potential interceptors. | ||
|  | 
 | ||
|  | 	This package has been planned to be used with OpenSSL, v. 0.9.5. | ||
|  | 	It requires the OpenSSL function RAND_add.  | ||
|  | 
 | ||
|  | --	OTHER WORK: Some source code and other details have been | ||
|  | 	published elsewhere, but I haven't found any to be satisfactory | ||
|  | 	for the Mac per se: | ||
|  | 
 | ||
|  | 	* The Linux random number generator (by Theodore Ts'o, in | ||
|  | 	  drivers/char/random.c), is a carefully designed open-source | ||
|  | 	  crypto random number package. It collects data from a variety | ||
|  | 	  of sources, including mouse, keyboard and other interrupts. | ||
|  | 	  One nice feature is that it explicitly estimates the entropy | ||
|  | 	  of the data it collects. Some of its features (e.g. interrupt | ||
|  | 	  timing) cannot be reliably exported to the Mac without using | ||
|  | 	  undocumented APIs. | ||
|  | 
 | ||
|  | 	* Truerand by Don P. Mitchell and Matt Blaze uses variations | ||
|  | 	  between different timing mechanisms on the same system. This | ||
|  | 	  has not been tested on the Mac, but requires preemptive | ||
|  | 	  multitasking, and is hardware-dependent, and can't be relied | ||
|  | 	  on to work well if only one oscillator is present. | ||
|  | 
 | ||
|  | 	* Cryptlib's RNG for the Mac (RNDMAC.C by Peter Gutmann), | ||
|  | 	  gathers a lot of information about the machine and system | ||
|  | 	  environment. Unfortunately, much of it is constant from one | ||
|  | 	  startup to the next. In other words, the random seed could be | ||
|  | 	  the same from one day to the next. Some of the APIs are | ||
|  | 	  hardware-dependent, and not all are compatible with Carbon (OS | ||
|  | 	  X). Incidentally, the EGD library is based on the UNIX entropy | ||
|  | 	  gathering methods in cryptlib, and isn't suitable for MacOS | ||
|  | 	  either. | ||
|  | 
 | ||
|  | 	* Mozilla (and perhaps earlier versions of Netscape) uses the | ||
|  | 	  time of day (in seconds) and an uninitialized local variable | ||
|  | 	  to seed the random number generator. The time of day is known | ||
|  | 	  to an outside interceptor (to within the accuracy of the | ||
|  | 	  system clock). The uninitialized variable could easily be | ||
|  | 	  identical between subsequent launches of an application, if it | ||
|  | 	  is reached through the same path. | ||
|  | 
 | ||
|  | 	* OpenSSL provides the function RAND_screen(), by G. van | ||
|  | 	  Oosten, which hashes the contents of the screen to generate a | ||
|  | 	  seed. This is not useful for an extension or for an | ||
|  | 	  application which launches at startup time, since the screen | ||
|  | 	  is likely to look identical from one launch to the next. This | ||
|  | 	  method is also rather slow. | ||
|  | 
 | ||
|  | 	* Using variations in disk drive seek times has been proposed | ||
|  | 	  (Davis, Ihaka and Fenstermacher, world.std.com/~dtd/; | ||
|  | 	  Jakobsson, Shriver, Hillyer and Juels, | ||
|  | 	  www.bell-labs.com/user/shriver/random.html). These variations | ||
|  | 	  appear to be due to air turbulence inside the disk drive | ||
|  | 	  mechanism, and are very strongly unpredictable. Unfortunately | ||
|  | 	  this technique is slow, and some implementations of it may be | ||
|  | 	  patented (see Shriver's page above.) It of course cannot be | ||
|  | 	  used with a RAM disk. | ||
|  | 
 | ||
|  | --	TIMING: On the 601 PowerPC the time base register is guaranteed | ||
|  | 	to change at least once every 10 addi instructions, i.e. 10 | ||
|  | 	cycles. On a 60 MHz machine (slowest PowerPC) this translates to | ||
|  | 	a resolution of 1/6 usec. Newer machines seem to be using a 10 | ||
|  | 	cycle resolution as well. | ||
|  | 	 | ||
|  | 	For 68K Macs, the Microseconds() call may be used. See Develop | ||
|  | 	issue 29 on the Apple developer site | ||
|  | 	(developer.apple.com/dev/techsupport/develop/issue29/minow.html) | ||
|  | 	for information on its accuracy and resolution. The code below | ||
|  | 	has been tested only on PowerPC based machines. | ||
|  | 
 | ||
|  | 	The time from machine startup to the launch of an application in | ||
|  | 	the startup folder has a variance of about 1.6 msec on a new G4 | ||
|  | 	machine with a defragmented and optimized disk, most extensions | ||
|  | 	off and no icons on the desktop. This can be reasonably taken as | ||
|  | 	a lower bound on the variance. Most of this variation is likely | ||
|  | 	due to disk seek time variability. The distribution of startup | ||
|  | 	times is probably not entirely even or uncorrelated. This needs | ||
|  | 	to be investigated, but I am guessing that it not a majpor | ||
|  | 	problem. Entropy = log2 (1600/0.166) ~= 13 bits on a 60 MHz | ||
|  | 	machine, ~16 bits for a 450 MHz machine. | ||
|  | 
 | ||
|  | 	User-launched application startup times will have a variance of | ||
|  | 	a second or more relative to machine startup time. Entropy >~22 | ||
|  | 	bits. | ||
|  | 
 | ||
|  | 	Machine startup time is available with a 1-second resolution. It | ||
|  | 	is predictable to no better a minute or two, in the case of | ||
|  | 	people who show up punctually to work at the same time and | ||
|  | 	immediately start their computer. Using the scheduled startup | ||
|  | 	feature (when available) will cause the machine to start up at | ||
|  | 	the same time every day, making the value predictable. Entropy | ||
|  | 	>~7 bits, or 0 bits with scheduled startup. | ||
|  | 
 | ||
|  | 	The time of day is of course known to an outsider and thus has 0 | ||
|  | 	entropy if the system clock is regularly calibrated. | ||
|  | 
 | ||
|  | --	KEY TIMING: A  very fast typist (120 wpm) will have a typical | ||
|  | 	inter-key timing interval of 100 msec. We can assume a variance | ||
|  | 	of no less than 2 msec -- maybe. Do good typists have a constant | ||
|  | 	rhythm, like drummers? Since what we measure is not the | ||
|  | 	key-generated interrupt but the time at which the key event was | ||
|  | 	taken off the event queue, our resolution is roughly the time | ||
|  | 	between process switches, at best 1 tick (17 msec). I  therefore | ||
|  | 	consider this technique questionable and not very useful for | ||
|  | 	obtaining high entropy data on the Mac. | ||
|  | 
 | ||
|  | --	MOUSE POSITION AND TIMING: The high bits of the mouse position | ||
|  | 	are far from arbitrary, since the mouse tends to stay in a few | ||
|  | 	limited areas of the screen. I am guessing that the position of | ||
|  | 	the mouse is arbitrary within a 6 pixel square. Since the mouse | ||
|  | 	stays still for long periods of time, it should be sampled only | ||
|  | 	after it was moved, to avoid correlated data. This gives an | ||
|  | 	entropy of log2(6*6) ~= 5 bits per measurement. | ||
|  | 
 | ||
|  | 	The time during which the mouse stays still can vary from zero | ||
|  | 	to, say, 5 seconds (occasionally longer). If the still time is | ||
|  | 	measured by sampling the mouse during null events, and null | ||
|  | 	events are received once per tick, its resolution is 1/60th of a | ||
|  | 	second, giving an entropy of log2 (60*5) ~= 8 bits per | ||
|  | 	measurement. Since the distribution of still times is uneven, | ||
|  | 	this estimate is on the high side. | ||
|  | 
 | ||
|  | 	For simplicity and compatibility across system versions, the | ||
|  | 	mouse is to be sampled explicitly (e.g. in the event loop), | ||
|  | 	rather than in a time manager task. | ||
|  | 
 | ||
|  | --	STARTUP DISK TOTAL FILE SIZE: Varies typically by at least 20k | ||
|  | 	from one startup to the next, with 'minimal' computer use. Won't | ||
|  | 	vary at all if machine is started again immediately after | ||
|  | 	startup (unless virtual memory is on), but any application which | ||
|  | 	uses the web and caches information to disk is likely to cause | ||
|  | 	this much variation or more. The variation is probably not | ||
|  | 	random, but I don't know in what way. File sizes tend to be | ||
|  | 	divisible by 4 bytes since file format fields are often | ||
|  | 	long-aligned. Entropy > log2 (20000/4) ~= 12 bits. | ||
|  | 	 | ||
|  | --	STARTUP DISK FIRST AVAILABLE ALLOCATION BLOCK: As the volume | ||
|  | 	gets fragmented this could be anywhere in principle. In a | ||
|  | 	perfectly unfragmented volume this will be strongly correlated | ||
|  | 	with the total file size on the disk. With more fragmentation | ||
|  | 	comes less certainty. I took the variation in this value to be | ||
|  | 	1/8 of the total file size on the volume. | ||
|  | 
 | ||
|  | --	SYSTEM REQUIREMENTS: The code here requires System 7.0 and above | ||
|  | 	(for Gestalt and Microseconds calls). All the calls used are | ||
|  | 	Carbon-compatible. | ||
|  | */ | ||
|  | 
 | ||
|  | /*------------------------------ Includes ----------------------------*/ | ||
|  | 
 | ||
|  | #include "Randomizer.h"
 | ||
|  | 
 | ||
|  | // Mac OS API
 | ||
|  | #include <Files.h>
 | ||
|  | #include <Folders.h>
 | ||
|  | #include <Events.h>
 | ||
|  | #include <Processes.h>
 | ||
|  | #include <Gestalt.h>
 | ||
|  | #include <Resources.h>
 | ||
|  | #include <LowMem.h>
 | ||
|  | 
 | ||
|  | // Standard C library
 | ||
|  | #include <stdlib.h>
 | ||
|  | #include <math.h>
 | ||
|  | 
 | ||
|  | /*---------------------- Function declarations -----------------------*/ | ||
|  | 
 | ||
|  | // declared in OpenSSL/crypto/rand/rand.h
 | ||
|  | extern "C" void RAND_add (const void *buf, int num, double entropy); | ||
|  | 
 | ||
|  | unsigned long GetPPCTimer (bool is601);	// Make it global if needed
 | ||
|  | 					// elsewhere
 | ||
|  | 
 | ||
|  | /*---------------------------- Constants -----------------------------*/ | ||
|  | 
 | ||
|  | #define kMouseResolution 6		// Mouse position has to differ
 | ||
|  | 					// from the last one by this
 | ||
|  | 					// much to be entered
 | ||
|  | #define kMousePositionEntropy 5.16	// log2 (kMouseResolution**2)
 | ||
|  | #define kTypicalMouseIdleTicks 300.0	// I am guessing that a typical
 | ||
|  | 					// amount of time between mouse
 | ||
|  | 					// moves is 5 seconds
 | ||
|  | #define kVolumeBytesEntropy 12.0	// about log2 (20000/4),
 | ||
|  | 					// assuming a variation of 20K
 | ||
|  | 					// in total file size and
 | ||
|  | 					// long-aligned file formats.
 | ||
|  | #define kApplicationUpTimeEntropy 6.0	// Variance > 1 second, uptime
 | ||
|  | 					// in ticks  
 | ||
|  | #define kSysStartupEntropy 7.0		// Entropy for machine startup
 | ||
|  | 					// time
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /*------------------------ Function definitions ----------------------*/ | ||
|  | 
 | ||
|  | CRandomizer::CRandomizer (void) | ||
|  | { | ||
|  | 	long	result; | ||
|  | 	 | ||
|  | 	mSupportsLargeVolumes = | ||
|  | 		(Gestalt(gestaltFSAttr, &result) == noErr) && | ||
|  | 		((result & (1L << gestaltFSSupports2TBVols)) != 0); | ||
|  | 	 | ||
|  | 	if (Gestalt (gestaltNativeCPUtype, &result) != noErr) | ||
|  | 	{ | ||
|  | 		mIsPowerPC = false; | ||
|  | 		mIs601 = false; | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		mIs601 = (result == gestaltCPU601); | ||
|  | 		mIsPowerPC = (result >= gestaltCPU601); | ||
|  | 	} | ||
|  | 	mLastMouse.h = mLastMouse.v = -10;	// First mouse will
 | ||
|  | 						// always be recorded
 | ||
|  | 	mLastPeriodicTicks = TickCount(); | ||
|  | 	GetTimeBaseResolution (); | ||
|  | 	 | ||
|  | 	// Add initial entropy
 | ||
|  | 	AddTimeSinceMachineStartup (); | ||
|  | 	AddAbsoluteSystemStartupTime (); | ||
|  | 	AddStartupVolumeInfo (); | ||
|  | 	AddFiller (); | ||
|  | } | ||
|  | 
 | ||
|  | void CRandomizer::PeriodicAction (void) | ||
|  | { | ||
|  | 	AddCurrentMouse (); | ||
|  | 	AddNow (0.0);	// Should have a better entropy estimate here
 | ||
|  | 	mLastPeriodicTicks = TickCount(); | ||
|  | } | ||
|  | 
 | ||
|  | /*------------------------- Private Methods --------------------------*/ | ||
|  | 
 | ||
|  | void CRandomizer::AddCurrentMouse (void) | ||
|  | { | ||
|  | 	Point mouseLoc; | ||
|  | 	unsigned long lastCheck;	// Ticks since mouse was last
 | ||
|  | 					// sampled
 | ||
|  | 
 | ||
|  | #if TARGET_API_MAC_CARBON
 | ||
|  | 	GetGlobalMouse (&mouseLoc); | ||
|  | #else
 | ||
|  | 	mouseLoc = LMGetMouseLocation(); | ||
|  | #endif
 | ||
|  | 	 | ||
|  | 	if (labs (mLastMouse.h - mouseLoc.h) > kMouseResolution/2 && | ||
|  | 	    labs (mLastMouse.v - mouseLoc.v) > kMouseResolution/2) | ||
|  | 		AddBytes (&mouseLoc, sizeof (mouseLoc), | ||
|  | 				kMousePositionEntropy); | ||
|  | 	 | ||
|  | 	if (mLastMouse.h == mouseLoc.h && mLastMouse.v == mouseLoc.v) | ||
|  | 		mMouseStill ++; | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		double entropy; | ||
|  | 		 | ||
|  | 		// Mouse has moved. Add the number of measurements for
 | ||
|  | 		// which it's been still. If the resolution is too
 | ||
|  | 		// coarse, assume the entropy is 0.
 | ||
|  | 
 | ||
|  | 		lastCheck = TickCount() - mLastPeriodicTicks; | ||
|  | 		if (lastCheck <= 0) | ||
|  | 			lastCheck = 1; | ||
|  | 		entropy = log2l | ||
|  | 			(kTypicalMouseIdleTicks/(double)lastCheck); | ||
|  | 		if (entropy < 0.0) | ||
|  | 			entropy = 0.0; | ||
|  | 		AddBytes (&mMouseStill, sizeof (mMouseStill), entropy); | ||
|  | 		mMouseStill = 0; | ||
|  | 	} | ||
|  | 	mLastMouse = mouseLoc; | ||
|  | } | ||
|  | 
 | ||
|  | void CRandomizer::AddAbsoluteSystemStartupTime (void) | ||
|  | { | ||
|  | 	unsigned long	now;		// Time in seconds since
 | ||
|  | 					// 1/1/1904
 | ||
|  | 	GetDateTime (&now); | ||
|  | 	now -= TickCount() / 60;	// Time in ticks since machine
 | ||
|  | 					// startup
 | ||
|  | 	AddBytes (&now, sizeof (now), kSysStartupEntropy); | ||
|  | } | ||
|  | 
 | ||
|  | void CRandomizer::AddTimeSinceMachineStartup (void) | ||
|  | { | ||
|  | 	AddNow (1.5);			// Uncertainty in app startup
 | ||
|  | 					// time is > 1.5 msec (for
 | ||
|  | 					// automated app startup).
 | ||
|  | } | ||
|  | 
 | ||
|  | void CRandomizer::AddAppRunningTime (void) | ||
|  | { | ||
|  | 	ProcessSerialNumber PSN; | ||
|  | 	ProcessInfoRec		ProcessInfo; | ||
|  | 	 | ||
|  | 	ProcessInfo.processInfoLength = sizeof (ProcessInfoRec); | ||
|  | 	ProcessInfo.processName = nil; | ||
|  | 	ProcessInfo.processAppSpec = nil; | ||
|  | 	 | ||
|  | 	GetCurrentProcess (&PSN); | ||
|  | 	GetProcessInformation (&PSN, &ProcessInfo); | ||
|  | 
 | ||
|  | 	// Now add the amount of time in ticks that the current process
 | ||
|  | 	// has been active
 | ||
|  | 
 | ||
|  | 	AddBytes (&ProcessInfo, sizeof (ProcessInfoRec), | ||
|  | 			kApplicationUpTimeEntropy); | ||
|  | } | ||
|  | 
 | ||
|  | void CRandomizer::AddStartupVolumeInfo (void) | ||
|  | { | ||
|  | 	short			vRefNum; | ||
|  | 	long			dirID; | ||
|  | 	XVolumeParam	pb; | ||
|  | 	OSErr			err; | ||
|  | 	 | ||
|  | 	if (!mSupportsLargeVolumes) | ||
|  | 		return; | ||
|  | 		 | ||
|  | 	FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder, | ||
|  | 			&vRefNum, &dirID); | ||
|  | 	pb.ioVRefNum = vRefNum; | ||
|  | 	pb.ioCompletion = 0; | ||
|  | 	pb.ioNamePtr = 0; | ||
|  | 	pb.ioVolIndex = 0; | ||
|  | 	err = PBXGetVolInfoSync (&pb); | ||
|  | 	if (err != noErr) | ||
|  | 		return; | ||
|  | 		 | ||
|  | 	// Base the entropy on the amount of space used on the disk and
 | ||
|  | 	// on the next available allocation block. A lot else might be
 | ||
|  | 	// unpredictable, so might as well toss the whole block in. See
 | ||
|  | 	// comments for entropy estimate justifications.
 | ||
|  | 
 | ||
|  | 	AddBytes (&pb, sizeof (pb), | ||
|  | 		kVolumeBytesEntropy + | ||
|  | 		log2l (((pb.ioVTotalBytes.hi - pb.ioVFreeBytes.hi) | ||
|  | 				* 4294967296.0D + | ||
|  | 			(pb.ioVTotalBytes.lo - pb.ioVFreeBytes.lo)) | ||
|  | 				/ pb.ioVAlBlkSiz - 3.0)); | ||
|  | } | ||
|  | 
 | ||
|  | /*
 | ||
|  | 	On a typical startup CRandomizer will come up with about 60 | ||
|  | 	bits of good, unpredictable data. Assuming no more input will | ||
|  | 	be available, we'll need some more lower-quality data to give | ||
|  | 	OpenSSL the 128 bits of entropy it desires. AddFiller adds some | ||
|  | 	relatively predictable data into the soup. | ||
|  | */ | ||
|  | 
 | ||
|  | void CRandomizer::AddFiller (void) | ||
|  | { | ||
|  | 	struct | ||
|  | 	{ | ||
|  | 		ProcessSerialNumber psn;	// Front process serial
 | ||
|  | 						// number
 | ||
|  | 		RGBColor	hiliteRGBValue;	// User-selected
 | ||
|  | 						// highlight color
 | ||
|  | 		long		processCount;	// Number of active
 | ||
|  | 						// processes
 | ||
|  | 		long		cpuSpeed;	// Processor speed
 | ||
|  | 		long		totalMemory;	// Total logical memory
 | ||
|  | 						// (incl. virtual one)
 | ||
|  | 		long		systemVersion;	// OS version
 | ||
|  | 		short		resFile;	// Current resource file
 | ||
|  | 	} data; | ||
|  | 	 | ||
|  | 	GetNextProcess ((ProcessSerialNumber*) kNoProcess); | ||
|  | 	while (GetNextProcess (&data.psn) == noErr) | ||
|  | 		data.processCount++; | ||
|  | 	GetFrontProcess (&data.psn); | ||
|  | 	LMGetHiliteRGB (&data.hiliteRGBValue); | ||
|  | 	Gestalt (gestaltProcClkSpeed, &data.cpuSpeed); | ||
|  | 	Gestalt (gestaltLogicalRAMSize, &data.totalMemory); | ||
|  | 	Gestalt (gestaltSystemVersion, &data.systemVersion); | ||
|  | 	data.resFile = CurResFile (); | ||
|  | 	 | ||
|  | 	// Here we pretend to feed the PRNG completely random data. This
 | ||
|  | 	// is of course false, as much of the above data is predictable
 | ||
|  | 	// by an outsider. At this point we don't have any more
 | ||
|  | 	// randomness to add, but with OpenSSL we must have a 128 bit
 | ||
|  | 	// seed before we can start. We just add what we can, without a
 | ||
|  | 	// real entropy estimate, and hope for the best.
 | ||
|  | 
 | ||
|  | 	AddBytes (&data, sizeof(data), 8.0 * sizeof(data)); | ||
|  | 	AddCurrentMouse (); | ||
|  | 	AddNow (1.0); | ||
|  | } | ||
|  | 
 | ||
|  | //-------------------  LOW LEVEL ---------------------
 | ||
|  | 
 | ||
|  | void CRandomizer::AddBytes (void *data, long size, double entropy) | ||
|  | { | ||
|  | 	RAND_add (data, size, entropy * 0.125);	// Convert entropy bits
 | ||
|  | 						// to bytes
 | ||
|  | } | ||
|  | 
 | ||
|  | void CRandomizer::AddNow (double millisecondUncertainty) | ||
|  | { | ||
|  | 	long time = SysTimer(); | ||
|  | 	AddBytes (&time, sizeof (time), log2l (millisecondUncertainty * | ||
|  | 			mTimebaseTicksPerMillisec)); | ||
|  | } | ||
|  | 
 | ||
|  | //----------------- TIMING SUPPORT ------------------
 | ||
|  | 
 | ||
|  | void CRandomizer::GetTimeBaseResolution (void) | ||
|  | {	 | ||
|  | #ifdef __powerc
 | ||
|  | 	long speed; | ||
|  | 	 | ||
|  | 	// gestaltProcClkSpeed available on System 7.5.2 and above
 | ||
|  | 	if (Gestalt (gestaltProcClkSpeed, &speed) != noErr) | ||
|  | 		// Only PowerPCs running pre-7.5.2 are 60-80 MHz
 | ||
|  | 		// machines.
 | ||
|  | 		mTimebaseTicksPerMillisec =  6000.0D; | ||
|  | 	// Assume 10 cycles per clock update, as in 601 spec. Seems true
 | ||
|  | 	// for later chips as well.
 | ||
|  | 	mTimebaseTicksPerMillisec = speed / 1.0e4D; | ||
|  | #else
 | ||
|  | 	// 68K VIA-based machines (see Develop Magazine no. 29)
 | ||
|  | 	mTimebaseTicksPerMillisec = 783.360D; | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | unsigned long CRandomizer::SysTimer (void)	// returns the lower 32
 | ||
|  | 						// bit of the chip timer
 | ||
|  | { | ||
|  | #ifdef __powerc
 | ||
|  | 	return GetPPCTimer (mIs601); | ||
|  | #else
 | ||
|  | 	UnsignedWide usec; | ||
|  | 	Microseconds (&usec); | ||
|  | 	return usec.lo; | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | #ifdef __powerc
 | ||
|  | // The timebase is available through mfspr on 601, mftb on later chips.
 | ||
|  | // Motorola recommends that an 601 implementation map mftb to mfspr
 | ||
|  | // through an exception, but I haven't tested to see if MacOS actually
 | ||
|  | // does this. We only sample the lower 32 bits of the timer (i.e. a
 | ||
|  | // few minutes of resolution)
 | ||
|  | 
 | ||
|  | asm unsigned long GetPPCTimer (register bool is601) | ||
|  | { | ||
|  | 	cmplwi	is601, 0	// Check if 601
 | ||
|  | 	bne	_601		// if non-zero goto _601
 | ||
|  | 	mftb  	r3		// Available on 603 and later.
 | ||
|  | 	blr			// return with result in r3
 | ||
|  | _601: | ||
|  | 	mfspr r3, spr5  	// Available on 601 only.
 | ||
|  | 				// blr inserted automatically
 | ||
|  | } | ||
|  | #endif
 |