diff --git a/core/c/README b/core/c/README
new file mode 100644
index 0000000000000000000000000000000000000000..229a8a83de99265bd9683cef4373c6b277235d72
--- /dev/null
+++ b/core/c/README
@@ -0,0 +1,9 @@
+Prior to building the jbigi library, you will need to fetch the GMP source
+from http://www.swox.com/gmp/, saving it to jbigi/gmp-4.1.3.tar.bz2 (it will
+be unpacked and built as necessary).
+
+To build the native jbigi and jcpuid libraries for the current host CPU,
+simply run sh build.sh and the results will be packaged up into jbigi.jar
+
+To build the native jbigi libraries for all supported CPUs (on the current OS),
+go into jbigi/ and run build-all.sh (the results will be under jbigi/lib/)
diff --git a/core/c/build.sh b/core/c/build.sh
index 233a795064129b9ff87faf1eeb2b501d83aa097a..ca2826dcf2648fd2065b6984e15fae6404e6dcad 100644
--- a/core/c/build.sh
+++ b/core/c/build.sh
@@ -1,40 +1,14 @@
-#!/bin/sh
-# linux settings:
-CC="gcc"
-ANT="ant"
-JAVA="java"
+#/bin/sh
 
-COMPILEFLAGS="-fPIC -Wall"
-LINKFLAGS="-shared -Wl,-soname,libjbigi.so"
+(cd jcpuid ; sh build.sh ; cd ..)
+(cd jbigi ; sh build.sh ; cd ..)
 
-INCLUDES="-Iinclude -I$JAVA_HOME/include -I$JAVA_HOME/include/linux"
-INCLUDELIBS="-lgmp"
-STATICLIBS=""
+mkdir -p t/freenet/support/CPUInformation/
+cp jcpuid/lib/freenet/support/CPUInformation/*jcpuid-* t/freenet/support/CPUInformation/
 
-LIBFILE="libjbigi.so"
+mkdir -p t/net/i2p/util/
+cp jbigi/lib/net/i2p/util/*jbigi-* t/net/i2p/util/
 
-# jrandom's mingw setup:
-#COMPILEFLAGS="-Wall"
-#INCLUDES="-Iinclude -Ic:/software/j2sdk1.4.2/include/win32/ -Ic:/software/j2sdk1.4.2/include/ -Ic:/dev/gmp-4.1.2/"
-#LINKFLAGS="-shared -Wl,--kill-at"
-#LIBFILE="jbigi.dll"
-#INCLUDELIBS=""
-#STATICLIBS="libgmp.a"
+(cd t ; jar cf ../jbigi.jar . ; cd ..)
 
-echo "Compiling C code..."
-rm -f jbigi.o $LIBFILE
-$CC -c $COMPILEFLAGS $INCLUDES src/jbigi.c
-$CC $LINKFLAGS $INCLUDES $INCLUDELIBS -o $LIBFILE jbigi.o $STATICLIBS
-
-echo ""
-echo "Doing an ant build..."
-(cd ../java/ ; $ANT build)
-
-echo ""
-echo "Built, now testing... This will take a while."
-LD_LIBRARY_PATH=. $JAVA -cp ../java/build/i2p.jar -DloggerConfigLocation=../../installer/java/src/logger.config.template net.i2p.util.NativeBigInteger
-
-
-echo ""
-echo ""
-echo "Test complete. Please review the lines 'native run time:', 'java run time:', and 'native = '"
+echo "Native code built into jbigi.jar"
diff --git a/core/c/jbigi/README b/core/c/jbigi/README
new file mode 100644
index 0000000000000000000000000000000000000000..b8417be99acd98ee4db6cc823dfd1de3644124a9
--- /dev/null
+++ b/core/c/jbigi/README
@@ -0,0 +1,13 @@
+***net.i2p.util.NativeBigInteger, native part of the code****
+
+Execute the build.sh script to produce jbigi library files optimized for a number of different CPU-types.
+
+TODO: What is jbigi
+TODO: Document generated folder structure
+TODO: Instructions for adding the libraries to a jar
+
+Linux-specific information:
+Some linux distributions comes bundled with GMP. There is currently no out-of-the-box support for this in the current build-scripts.
+
+Windows-specific information:
+The best way of building the jbigi dll's is to install Mingw {URL} and msys {URL}. The combination of these two should be able to run the included build-scripts without modifications.
\ No newline at end of file
diff --git a/core/c/jbigi/build-all.sh b/core/c/jbigi/build-all.sh
new file mode 100644
index 0000000000000000000000000000000000000000..0b1502724889ce2d8e8b57d1f4641d1b4b2685b2
--- /dev/null
+++ b/core/c/jbigi/build-all.sh
@@ -0,0 +1,40 @@
+#/bin/sh
+
+case `uname -sr` in
+MINGW*)
+	echo "Building windows .dlls for all architectures";;
+Linux*)
+	echo "Building linux .sos for all architectures";;
+FreeBSD*)
+	echo "Building freebsd .sos for all architectures";;
+*)
+	echo "Unsupported build environment"
+	exit;;
+esac
+
+echo "Extracting GMP..."
+tar -xzf gmp-4.1.3.tar.gz
+echo "Building..."
+mkdir bin
+mkdir lib
+mkdir lib/net
+mkdir lib/net/i2p
+mkdir lib/net/i2p/util
+for x in none pentium pentiummmx pentium2 pentium3 pentium4 k6 k62 k63 athlon
+do
+	mkdir bin/$x
+	cd bin/$x
+	../../gmp-4.1.3/configure --build=$x
+	make
+	sh ../../build_jbigi.sh static
+	case `uname -sr` in
+	MINGW*)
+		cp jbigi.dll ../../lib/net/i2p/util/jbigi-windows-$x.dll;;
+	Linux*)
+		cp libjbigi.so ../../lib/net/i2p/util/libjbigi-linux-$x.so;;
+	FreeBSD*)
+		cp libjbigi.so ../../lib/net/i2p/util/libjbigi-freebsd-$x.so;;
+	esac
+	cd ..
+	cd ..
+done
diff --git a/core/c/jbigi/build.sh b/core/c/jbigi/build.sh
new file mode 100644
index 0000000000000000000000000000000000000000..1a6ca48a349fe3e56d8f7e056863b29a15cf1697
--- /dev/null
+++ b/core/c/jbigi/build.sh
@@ -0,0 +1,41 @@
+#/bin/sh
+
+case `uname -sr` in
+MINGW*)
+	echo "Building windows .dll's";;
+CYGWIN*)
+	echo "Building windows .dll's";;
+Linux*)
+	echo "Building linux .so's";;
+FreeBSD*)
+	echo "Building freebsd .so's";;
+*)
+	echo "Unsupported build environment"
+	exit;;
+esac
+
+echo "Extracting GMP..."
+tar -xzf gmp-4.1.3.tar.gz
+echo "Building..."
+mkdir bin
+mkdir lib
+mkdir lib/net
+mkdir lib/net/i2p
+mkdir lib/net/i2p/util
+mkdir bin/local
+cd bin/local
+../../gmp-4.1.3/configure
+make
+sh ../../build_jbigi.sh static
+case `uname -sr` in
+MINGW*)
+	cp jbigi.dll ../../lib/net/i2p/util/jbigi-windows-x86.dll;;
+CYGWIN*)
+	cp jbigi.dll ../../lib/net/i2p/util/jbigi-windows-x86.dll;;
+Linux*)
+	cp libjbigi.so ../../lib/net/i2p/util/libjbigi-linux-x86.so;;
+FreeBSD*)
+	cp libjbigi.so ../../lib/net/i2p/util/libjbigi-freebsd-x86.so;;
+esac
+cd ..
+cd ..
diff --git a/core/c/jbigi/build_jbigi.sh b/core/c/jbigi/build_jbigi.sh
new file mode 100644
index 0000000000000000000000000000000000000000..54b0a36739eee3a4ec807370e02a0edb28c6b45a
--- /dev/null
+++ b/core/c/jbigi/build_jbigi.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# When executed in Mingw: Produces an jbigi.dll
+# When executed in Linux: Produces an libjbigi.so
+
+CC="gcc"
+
+case `uname -sr` in
+MINGW*)
+	JAVA_HOME="c:/software/j2sdk1.4.2_05"
+	COMPILEFLAGS="-Wall"
+	INCLUDES="-I. -I../../jbigi/include -I$JAVA_HOME/include/win32/ -I$JAVA_HOME/include/"
+	LINKFLAGS="-shared -Wl,--kill-at"
+	LIBFILE="jbigi.dll";;
+CYGWIN*)
+	JAVA_HOME="c:/software/j2sdk1.4.2_05"
+	COMPILEFLAGS="-Wall -mno-cygwin"
+	INCLUDES="-I. -I../../jbigi/include -I$JAVA_HOME/include/win32/ -I$JAVA_HOME/include/"
+	LINKFLAGS="-shared -Wl,--kill-at"
+	LIBFILE="jbigi.dll";;
+*)
+	COMPILEFLAGS="-fPIC -Wall"
+	INCLUDES="-I. -I../../jbigi/include -I$JAVA_HOME/include -I$JAVA_HOME/include/linux"
+	LINKFLAGS="-shared -Wl,-soname,libjbigi.so"
+	LIBFILE="libjbigi.so";;
+esac
+
+#To link dynamically to GMP (use libgmp.so or gmp.lib), uncomment the first line below
+#To link statically to GMP, uncomment the second line below
+if test $1 = "dynamic"
+then
+	echo "Building jbigi lib that is dynamically linked to GMP" 
+	LIBPATH="-L.libs"
+	INCLUDELIBS="-lgmp"
+else
+	echo "Building jbigi lib that is statically linked to GMP"
+	STATICLIBS=".libs/libgmp.a"
+fi
+
+echo "Compiling C code..."
+rm -f jbigi.o $LIBFILE
+$CC -c $COMPILEFLAGS $INCLUDES ../../jbigi/src/jbigi.c
+$CC $LINKFLAGS $INCLUDES $INCLUDELIBS -o $LIBFILE jbigi.o $STATICLIBS
diff --git a/core/c/jbigi/jbigi/include/jbigi.h b/core/c/jbigi/jbigi/include/jbigi.h
new file mode 100644
index 0000000000000000000000000000000000000000..1b1c1c26314604289f5c7c7e4b58cf43ce3c243c
--- /dev/null
+++ b/core/c/jbigi/jbigi/include/jbigi.h
@@ -0,0 +1,62 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class net_i2p_util_NativeBigInteger */
+
+#ifndef _Included_net_i2p_util_NativeBigInteger
+#define _Included_net_i2p_util_NativeBigInteger
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef net_i2p_util_NativeBigInteger_serialVersionUID
+#define net_i2p_util_NativeBigInteger_serialVersionUID -8742448824652078965i64
+#undef net_i2p_util_NativeBigInteger_LONG_MASK
+#define net_i2p_util_NativeBigInteger_LONG_MASK 4294967295i64
+/* Inaccessible static: bitsPerDigit */
+#undef net_i2p_util_NativeBigInteger_SMALL_PRIME_THRESHOLD
+#define net_i2p_util_NativeBigInteger_SMALL_PRIME_THRESHOLD 95L
+/* Inaccessible static: SMALL_PRIME_PRODUCT */
+#undef net_i2p_util_NativeBigInteger_MAX_CONSTANT
+#define net_i2p_util_NativeBigInteger_MAX_CONSTANT 16L
+/* Inaccessible static: posConst */
+/* Inaccessible static: negConst */
+/* Inaccessible static: ZERO */
+/* Inaccessible static: ONE */
+/* Inaccessible static: TWO */
+/* Inaccessible static: bnExpModThreshTable */
+/* Inaccessible static: trailingZeroTable */
+/* Inaccessible static: zeros */
+/* Inaccessible static: digitsPerLong */
+/* Inaccessible static: longRadix */
+/* Inaccessible static: digitsPerInt */
+/* Inaccessible static: intRadix */
+#undef net_i2p_util_NativeBigInteger_serialVersionUID
+#define net_i2p_util_NativeBigInteger_serialVersionUID -8287574255936472291i64
+/* Inaccessible static: serialPersistentFields */
+/* Inaccessible static: array_00024B */
+/* Inaccessible static: _nativeOk */
+#undef net_i2p_util_NativeBigInteger__doLog
+#define net_i2p_util_NativeBigInteger__doLog 1L
+/* Inaccessible static: DEFAULT_REF_FILENAME */
+/* Inaccessible static: _sampleGenerator */
+/* Inaccessible static: _samplePrime */
+/* Inaccessible static: class_000240 */
+/*
+ * Class:     net_i2p_util_NativeBigInteger
+ * Method:    nativeModPow
+ * Signature: ([B[B[B)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_net_i2p_util_NativeBigInteger_nativeModPow
+  (JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray);
+
+/*
+ * Class:     net_i2p_util_NativeBigInteger
+ * Method:    nativeDoubleValue
+ * Signature: ([B)D
+ */
+JNIEXPORT jdouble JNICALL Java_net_i2p_util_NativeBigInteger_nativeDoubleValue
+  (JNIEnv *, jclass, jbyteArray);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/core/c/jbigi/jbigi/src/jbigi.c b/core/c/jbigi/jbigi/src/jbigi.c
new file mode 100644
index 0000000000000000000000000000000000000000..a0aea5b94d665392bcb9340e332ed88f5b362bf8
--- /dev/null
+++ b/core/c/jbigi/jbigi/src/jbigi.c
@@ -0,0 +1,178 @@
+#include <stdio.h>
+#include <gmp.h>
+#include "jbigi.h"
+
+/******** prototypes */
+
+void convert_j2mp(JNIEnv* env, jbyteArray jvalue, mpz_t* mvalue);
+void convert_mp2j(JNIEnv* env, mpz_t mvalue, jbyteArray* jvalue);
+
+
+/*****************************************
+ *****Native method implementations*******
+ *****************************************/
+
+/******** nativeModPow() */
+/*
+ * Class:     net_i2p_util_NativeBigInteger
+ * Method:    nativeModPow
+ * Signature: ([B[B[B)[B
+ *
+ * From the javadoc:
+ *
+ * calculate (base ^ exponent) % modulus.
+ * @param curVal big endian twos complement representation of the base (but it must be positive)
+ * @param exponent big endian twos complement representation of the exponent
+ * @param modulus big endian twos complement representation of the modulus
+ * @return big endian twos complement representation of (base ^ exponent) % modulus
+ */
+
+JNIEXPORT jbyteArray JNICALL Java_net_i2p_util_NativeBigInteger_nativeModPow
+        (JNIEnv* env, jclass cls, jbyteArray jbase, jbyteArray jexp, jbyteArray jmod) {
+        /* 1) Convert base, exponent, modulus into the format libgmp understands
+         * 2) Call libgmp's modPow.
+         * 3) Convert libgmp's result into a big endian twos complement number.
+         */
+
+        mpz_t mbase;
+        mpz_t mexp;
+        mpz_t mmod;
+        jbyteArray jresult;
+
+        convert_j2mp(env, jbase, &mbase);
+        convert_j2mp(env, jexp,  &mexp);
+        convert_j2mp(env, jmod,  &mmod);
+ 
+		/* Perform the actual powmod. We use mmod for the result because it is
+         * always at least as big as the result.
+         */
+        mpz_powm(mmod, mbase, mexp, mmod);
+
+		convert_mp2j(env, mmod, &jresult);
+
+        mpz_clear(mbase);
+        mpz_clear(mexp);
+        mpz_clear(mmod);
+
+        return jresult;
+}
+
+/******** nativeDoubleValue() */
+/*
+ * Class:     net_i2p_util_NativeBigInteger
+ * Method:    nativeDoubleValue
+ * Signature: ([B)D
+ *
+ * From the Javadoc:
+ *
+ * Converts a BigInteger byte-array to a 'double'
+ * @param ba Big endian twos complement representation of the BigInteger to convert to a double
+ * @return The plain double-value represented by 'ba'
+ */
+JNIEXPORT jdouble JNICALL Java_net_i2p_util_NativeBigInteger_nativeDoubleValue
+(JNIEnv * env, jclass cls, jbyteArray jba){
+	    /* 1) Convert the bytearray BigInteger value into the format libgmp understands
+         * 2) Call libgmp's mpz_get_d.
+         * 3) Convert libgmp's result into a big endian twos complement number.
+         */
+        mpz_t mval;
+		jdouble retval;
+        convert_j2mp(env, jba, &mval);
+
+		retval = mpz_get_d(mval);
+		mpz_clear(mval);
+		return retval;
+}
+
+/******************************
+ *****Conversion methods*******
+ ******************************/
+
+/*Luckily we can use GMP's mpz_import() and mpz_export() functions to convert from/to
+ *BigInteger.toByteArray() representation.
+ */
+
+/******** convert_j2mp() */
+/*
+ * Initializes the GMP value with enough preallocated size, and converts the
+ * Java value into the GMP value. The value that mvalue points to should be
+ * uninitialized
+ */
+
+void convert_j2mp(JNIEnv* env, jbyteArray jvalue, mpz_t* mvalue)
+{
+        jsize size;
+        jbyte* jbuffer;
+		//int sign;
+
+        size = (*env)->GetArrayLength(env, jvalue);
+        jbuffer = (*env)->GetByteArrayElements(env, jvalue, NULL);
+
+        mpz_init2(*mvalue, sizeof(jbyte) * 8 * size); //preallocate the size
+
+        /* void mpz_import(
+         *   mpz_t rop, size_t count, int order, int size, int endian,
+         *   size_t nails, const void *op);
+         *
+         * order = 1
+         *   order can be 1 for most significant word first or -1 for least
+         *   significant first.
+         * endian = 1
+         *   Within each word endian can be 1 for most significant byte first,
+         *   -1 for least significant first.
+         * nails = 0
+         *   The most significant nails bits of each word are skipped, this can
+         *   be 0 to use the full words.
+         */
+        mpz_import(*mvalue, size, 1, sizeof(jbyte), 1, 0, (void*)jbuffer);
+		/*Uncomment this to support negative integer values,
+		not tested though..
+		sign = jbuffer[0] < 0?-1:1;
+		if(sign == -1)
+			mpz_neg(*mvalue,*mvalue);
+		*/
+        (*env)->ReleaseByteArrayElements(env, jvalue, jbuffer, JNI_ABORT);
+}
+
+/******** convert_mp2j() */
+/*
+ * Converts the GMP value into the Java value; Doesn't do anything else.
+ * Pads the resulting jbyte array with 0, so the twos complement value is always
+ * positive.
+ */
+
+void convert_mp2j(JNIEnv* env, mpz_t mvalue, jbyteArray* jvalue)
+{
+        jsize size;
+        jbyte* buffer;
+        jboolean copy;
+		//int i;
+
+        copy = JNI_FALSE;
+
+        /* sizeinbase() + 7 => Ceil division */
+        size = (mpz_sizeinbase(mvalue, 2) + 7) / 8 + sizeof(jbyte);
+        *jvalue = (*env)->NewByteArray(env, size);
+
+        buffer = (*env)->GetByteArrayElements(env, *jvalue, &copy);
+        buffer[0] = 0x00;
+		//Uncomment the comments below to support negative integer values,
+		//not very well-tested though..
+		//if(mpz_sgn(mvalue) >=0){
+		mpz_export((void*)&buffer[1], &size, 1, sizeof(jbyte), 1, 0, mvalue);
+		//}else{
+		//	mpz_add_ui(mvalue,mvalue,1);
+		//	mpz_export((void*)&buffer[1], &size, 1, sizeof(jbyte), 1, 0, mvalue);
+		//	for(i =0;i<=size;i++){ //This could be done more effectively
+		//		buffer[i]=~buffer[i];
+		//	}
+		//}
+
+		/* mode has (supposedly) no effect if elems is not a copy of the
+         * elements in array
+         */
+        (*env)->ReleaseByteArrayElements(env, *jvalue, buffer, 0);
+        //mode has (supposedly) no effect if elems is not a copy of the elements in array
+}
+
+/******** eof */
diff --git a/core/c/jcpuid/build.sh b/core/c/jcpuid/build.sh
new file mode 100644
index 0000000000000000000000000000000000000000..72ac5dec6ce1e1ecdb00243dc3cc90b4c5325b3d
--- /dev/null
+++ b/core/c/jcpuid/build.sh
@@ -0,0 +1,52 @@
+#/bin/sh
+
+case `uname -sr` in
+MINGW*)
+	echo "Building windows .dll's";;
+CYGWIN*)
+	echo "Building windows .dll's";;
+Linux*)
+	echo "Building linux .so's";;
+FreeBSD*)
+	echo "Building freebsd .so's";;
+*)
+	echo "Unsupported build environment"
+	exit;;
+esac
+
+rm -rf lib
+mkdir lib
+mkdir lib/freenet
+mkdir lib/freenet/support
+mkdir lib/freenet/support/CPUInformation
+
+CPP="g++"
+
+case `uname -sr` in
+MINGW*)
+	JAVA_HOME="/c/software/j2sdk1.4.2_05"
+	COMPILEFLAGS="-Wall"
+	INCLUDES="-I. -Iinclude -I$JAVA_HOME/include/ -I$JAVA_HOME/include/win32/"
+	LINKFLAGS="-shared -static -static-libgcc -Wl,--kill-at"
+	LIBFILE="lib/freenet/support/CPUInformation/jcpuid-x86-windows.dll";;
+FreeBSD*)
+	COMPILEFLAGS="-Wall"
+	INCLUDES="-I. -Iinclude -I$JAVA_HOME/include/ -I$JAVA_HOME/include/freebsd/"
+	LINKFLAGS="-shared -static -static-libgcc -Wl,-soname,libjcpuid-x86-freebsd.so"
+	LIBFILE="lib/freenet/support/CPUInformation/libjcpuid-x86-freebsd.so";;
+Linux*)
+	COMPILEFLAGS="-fPIC -Wall"
+	INCLUDES="-I. -Iinclude -I$JAVA_HOME/include -I$JAVA_HOME/include/linux"
+	LINKFLAGS="-shared -static -static-libgcc -Wl,-soname,libjcpuid-x86-linux.so"
+	LIBFILE="lib/freenet/support/CPUInformation/libjcpuid-x86-linux.so";;
+esac
+
+echo "Compiling C code..."
+rm -f $LIBFILE
+$CPP $LINKFLAGS $INCLUDES src/*.cpp -o $LIBFILE
+strip $LIBFILE
+echo Built $LIBFILE
+
+#g++ -shared -static -static-libgcc -Iinclude -I$JAVA_HOME/include \
+#    -I$JAVA_HOME/include/linux src/*.cpp \
+#    -o lib/freenet/support/CPUInformation/libjcpuid-x86-linux.so
diff --git a/core/c/jcpuid/include/jcpuid.h b/core/c/jcpuid/include/jcpuid.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff8cbbe28c03e14db0e657d6eb47cd4a13e2c67e
--- /dev/null
+++ b/core/c/jcpuid/include/jcpuid.h
@@ -0,0 +1,21 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class freenet_support_CPUInformation_CPUID */
+
+#ifndef _Included_freenet_support_CPUInformation_CPUID
+#define _Included_freenet_support_CPUInformation_CPUID
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     freenet_support_CPUInformation_CPUID
+ * Method:    doCPUID
+ * Signature: (I)Lfreenet/support/CPUInformation/CPUID$CPUIDResult;
+ */
+JNIEXPORT jobject JNICALL Java_freenet_support_CPUInformation_CPUID_doCPUID
+  (JNIEnv *, jclass, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/core/c/jcpuid/msvc/IMPORTANT.txt b/core/c/jcpuid/msvc/IMPORTANT.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0b9bdb00822ff2f7edd5c75e90737bde2c41732f
--- /dev/null
+++ b/core/c/jcpuid/msvc/IMPORTANT.txt
@@ -0,0 +1,2 @@
+You will need to rename the 'cpuinformation' par of the output folder '..\lib\freenet\support\cpuinformation' to 'CPUInformation' before importing the files to a .jar.
+Unfortunately MSVC doesn't respect the casing of the entered output folder.
\ No newline at end of file
diff --git a/core/c/jcpuid/msvc/jcpuid.sln b/core/c/jcpuid/msvc/jcpuid.sln
new file mode 100644
index 0000000000000000000000000000000000000000..d06efb411cb6f5804a37463f310225c79117bb7a
--- /dev/null
+++ b/core/c/jcpuid/msvc/jcpuid.sln
@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jcpuid", "jcpuid.vcproj", "{161B6AD9-3825-4BA5-893D-D90B09846849}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(DPCodeReviewSolutionGUID) = preSolution
+		DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000}
+	EndGlobalSection
+	GlobalSection(SolutionConfiguration) = preSolution
+		Debug = Debug
+		Release = Release
+	EndGlobalSection
+	GlobalSection(ProjectConfiguration) = postSolution
+		{161B6AD9-3825-4BA5-893D-D90B09846849}.Debug.ActiveCfg = Debug|Win32
+		{161B6AD9-3825-4BA5-893D-D90B09846849}.Debug.Build.0 = Debug|Win32
+		{161B6AD9-3825-4BA5-893D-D90B09846849}.Release.ActiveCfg = Release|Win32
+		{161B6AD9-3825-4BA5-893D-D90B09846849}.Release.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+	EndGlobalSection
+	GlobalSection(ExtensibilityAddIns) = postSolution
+	EndGlobalSection
+EndGlobal
diff --git a/core/c/jcpuid/msvc/jcpuid.suo b/core/c/jcpuid/msvc/jcpuid.suo
new file mode 100644
index 0000000000000000000000000000000000000000..5ce68a32238298f8c2eb94e334f60061dcb0a6d9
Binary files /dev/null and b/core/c/jcpuid/msvc/jcpuid.suo differ
diff --git a/core/c/jcpuid/msvc/jcpuid.vcproj b/core/c/jcpuid/msvc/jcpuid.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..1b1c6b1f6d8c9aac1f7a62871136111053285368
--- /dev/null
+++ b/core/c/jcpuid/msvc/jcpuid.vcproj
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="jcpuid"
+	ProjectGUID="{161B6AD9-3825-4BA5-893D-D90B09846849}"
+	RootNamespace="jcpuid"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="..\lib\freenet\support\CPUInformation"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;jcpuid_EXPORTS"
+				MinimalRebuild="TRUE"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="4"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/jcpuid-x86-windows.dll"
+				LinkIncremental="2"
+				GenerateDebugInformation="TRUE"
+				ProgramDatabaseFile="$(OutDir)/jcpuid.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/jcpuid.lib"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="..\lib\freenet\support\CPUInformation"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(SolutionDir)\..\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;jcpuid_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="3"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/jcpuid-x86-windows.dll"
+				LinkIncremental="1"
+				GenerateDebugInformation="TRUE"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/jcpuid.lib"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath="..\src\jcpuid.cpp">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath="..\include\jcpuid.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/core/c/jcpuid/src/jcpuid.cpp b/core/c/jcpuid/src/jcpuid.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e3ddba9c451343344b051264a5a365135521e26e
--- /dev/null
+++ b/core/c/jcpuid/src/jcpuid.cpp
@@ -0,0 +1,35 @@
+#include "jcpuid.h"
+
+//Executes the indicated subfunction of the CPUID operation
+JNIEXPORT jobject JNICALL Java_freenet_support_CPUInformation_CPUID_doCPUID
+  (JNIEnv * env, jclass cls, jint iFunction)
+{
+	int a,b,c,d;
+	jclass clsResult = env->FindClass ("freenet/support/CPUInformation/CPUID$CPUIDResult");
+	jmethodID constructor = env->GetMethodID(clsResult,"<init>","(IIII)V" );
+	#ifdef _MSC_VER
+		//Use MSVC assembler notation
+		_asm 
+		{
+			mov eax, iFunction
+			cpuid
+			mov a, eax
+			mov b, ebx
+			mov c, ecx
+			mov d, edx
+		}
+	#else
+		//Use GCC assembler notation
+		asm 
+		(
+			"cpuid"
+			: "=a" (a),
+			  "=b" (b),
+			  "=c"(c),
+			  "=d"(d)
+			:"a"(iFunction)
+		);
+	#endif
+	return env->NewObject(clsResult,constructor,a,b,c,d);
+}
+
diff --git a/core/java/src/freenet/support/CPUInformation/AMDCPUInfo.java b/core/java/src/freenet/support/CPUInformation/AMDCPUInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4fc2320939baea748d7e7236b238df5eefae080
--- /dev/null
+++ b/core/java/src/freenet/support/CPUInformation/AMDCPUInfo.java
@@ -0,0 +1,39 @@
+/*
+ * Created on Jul 17, 2004
+ *
+ */
+package freenet.support.CPUInformation;
+
+/**
+ * @author Iakin
+ * An interface for classes that provide lowlevel information about AMD CPU's
+ *
+ * free (adj.): unencumbered; not under the control of others
+ * Written by Iakin in 2004 and released into the public domain 
+ * with no warranty of any kind, either expressed or implied.  
+ * It probably won't make your computer catch on fire, or eat 
+ * your children, but it might. Use at your own risk.
+ */
+public interface AMDCPUInfo extends CPUInfo {
+    /**
+     * @return true iff the CPU present in the machine is at least an 'k6' CPU
+     */
+    public boolean IsK6Compatible();
+    /**
+     * @return true iff the CPU present in the machine is at least an 'k6-2' CPU
+     */
+    public boolean IsK6_2_Compatible();
+    /**
+     * @return true iff the CPU present in the machine is at least an 'k6-3' CPU
+     */
+    public boolean IsK6_3_Compatible();
+
+    /**
+     * @return true iff the CPU present in the machine is at least an 'k7' CPU (Atlhon, Duron etc. and better)
+     */
+    public boolean IsAthlonCompatible();
+    /**
+     * @return true iff the CPU present in the machine is at least an 'k8' CPU (Atlhon 64, Opteron etc. and better)
+     */
+    public boolean IsAthlon64Compatible();
+}
diff --git a/core/java/src/freenet/support/CPUInformation/CPUID.java b/core/java/src/freenet/support/CPUInformation/CPUID.java
new file mode 100644
index 0000000000000000000000000000000000000000..51f3b1b9ced6a6ea33dd0c67f2ccb5b21e7927f1
--- /dev/null
+++ b/core/java/src/freenet/support/CPUInformation/CPUID.java
@@ -0,0 +1,553 @@
+/*
+ * Created on Jul 14, 2004
+ */
+package freenet.support.CPUInformation;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * @author Iakin
+ * A class for retrieveing details about the CPU using the CPUID assembly instruction.
+ * A good resource for information about the CPUID instruction can be found here:
+ * http://www.paradicesoftware.com/specs/cpuid/index.htm
+ * 
+ * free (adj.): unencumbered; not under the control of others
+ * Written by Iakin in 2004 and released into the public domain 
+ * with no warranty of any kind, either expressed or implied.  
+ * It probably won't make your computer catch on fire, or eat 
+ * your children, but it might. Use at your own risk.
+*/
+
+public class CPUID {
+
+    /** did we load the native lib correctly? */
+    private static boolean _nativeOk = false;
+    
+    /** 
+     * do we want to dump some basic success/failure info to stderr during 
+     * initialization?  this would otherwise use the Log component, but this makes
+     * it easier for other systems to reuse this class
+     */
+    private static final boolean _doLog = true;
+
+    //.matches() is a java 1.4+ addition, using a simplified version for 1.3+
+    //private static final boolean isX86 = System.getProperty("os.arch").toLowerCase().matches("i?[x0-9]86(_64)?");
+    private static final boolean isX86 = (-1 != System.getProperty("os.arch").indexOf("86"));
+    
+    static
+    {
+        loadNative();
+    }
+    
+    //A class that can (amongst other things I assume) represent the state of the
+    //different CPU registers after a call to the CPUID assembly method
+    protected static class CPUIDResult {
+        final int EAX;
+        final int EBX;
+        final int ECX;
+        final int EDX;
+        CPUIDResult(int EAX,int EBX,int ECX, int EDX)
+        {
+            this.EAX = EAX;
+            this.EBX = EBX;
+            this.ECX = ECX;
+            this.EDX = EDX;
+        }
+    }
+    
+    /**Calls the indicated CPUID function and returns the result of the execution
+     * 
+     * @param iFunction The CPUID function to call, should be 0 or larger
+     * @return The contents of the CPU registers after the call to the CPUID function
+     */
+    private static native CPUIDResult doCPUID(int iFunction);
+
+    private static String getCPUVendorID()
+    {
+        CPUIDResult c = doCPUID(0);
+        StringBuffer sb= new StringBuffer(13);
+        sb.append((char)( c.EBX        & 0xFF));
+        sb.append((char)((c.EBX >> 8)  & 0xFF));
+        sb.append((char)((c.EBX >> 16) & 0xFF));
+        sb.append((char)((c.EBX >> 24) & 0xFF));
+        
+        sb.append((char)( c.EDX        & 0xFF));
+        sb.append((char)((c.EDX >> 8)  & 0xFF));
+        sb.append((char)((c.EDX >> 16) & 0xFF));
+        sb.append((char)((c.EDX >> 24) & 0xFF));
+        
+        sb.append((char)( c.ECX        & 0xFF));
+        sb.append((char)((c.ECX >> 8)  & 0xFF));
+        sb.append((char)((c.ECX >> 16) & 0xFF));
+        sb.append((char)((c.ECX >> 24) & 0xFF));
+    
+        return sb.toString();
+    }
+    private static int getCPUFamily()
+    {
+        CPUIDResult c = doCPUID(1);
+        return (c.EAX >> 8) & 0xf;
+    }
+    private static int getCPUModel()
+    {
+        CPUIDResult c = doCPUID(1);
+        return (c.EAX >> 4) & 0xf;
+    }
+    private static int getCPUExtendedModel()
+    {
+        CPUIDResult c = doCPUID(1);
+        return (c.EAX >> 16) & 0xf;
+    }
+    private static int getCPUType()
+    {
+        CPUIDResult c = doCPUID(1);
+        return (c.EAX >> 12) & 0xf;
+    }
+    private static int getCPUExtendedFamily()
+    {
+        CPUIDResult c = doCPUID(1);
+        return (c.EAX >> 20) & 0xff;
+    }
+    private static int getCPUStepping()
+    {
+        CPUIDResult c = doCPUID(1);
+        return c.EAX & 0xf;
+    }
+    private static int getCPUFlags()
+    {
+        CPUIDResult c = doCPUID(1);
+        return c.EDX;
+    }
+    
+    //Returns a CPUInfo item for the current type of CPU
+    //If I could I would declare this method in a interface named
+    //CPUInfoProvider and implement that interface in this class.
+    //This would make it easier for other people to understand that there
+    //is nothing preventing them from coding up new providers, probably using
+    //other detection methods than the x86-only CPUID instruction
+    public static CPUInfo getInfo() throws UnknownCPUException
+    {
+        if(!_nativeOk)
+            throw new UnknownCPUException("Failed to read CPU information from the system. Please verify the existence of the jcpuid dll/so.");
+        if(!isX86)
+            throw new UnknownCPUException("Failed to read CPU information from the system. The CPUID instruction exists on x86 CPU's only");
+        if(getCPUVendorID().equals("AuthenticAMD"))
+            return new AMDInfoImpl();
+        if(getCPUVendorID().equals("GenuineIntel"))
+            return new IntelInfoImpl();
+        throw new UnknownCPUException("Unknown CPU type: '"+getCPUVendorID()+"'");
+    }
+    
+    protected abstract static class CPUIDCPUInfo
+    {
+        public String getVendor()
+        {
+            return getCPUVendorID();
+        }
+        public boolean hasMMX(){
+            return (getCPUFlags() & 0x800000) >0; //Bit 23
+        }
+        public boolean hasSSE(){
+            return (getCPUFlags() & 0x2000000) >0; //Bit 25
+        }
+        public boolean hasSSE2(){
+            return (getCPUFlags() & 0x4000000) >0; //Bit 26
+        }
+    }
+    protected static class AMDInfoImpl extends CPUIDCPUInfo implements AMDCPUInfo
+    {
+        public boolean IsK6Compatible()
+        {
+            return getCPUFamily() >= 5 && getCPUModel() >= 6;
+        }
+        public boolean IsK6_2_Compatible()
+        {
+            return getCPUFamily() >= 5 && getCPUModel() >= 8;
+        }
+        public boolean IsK6_3_Compatible()
+        {
+            return getCPUFamily() >= 5 && getCPUModel() >= 9;
+        }
+        public boolean IsAthlonCompatible()
+        {
+            return getCPUFamily() >= 6;
+        }
+        public boolean IsAthlon64Compatible()
+        {
+            return getCPUFamily() == 15 && getCPUExtendedFamily() == 0;
+        }
+
+        public String getCPUModelString() throws UnknownCPUException
+        {
+            if(getCPUFamily() == 4){
+                switch(getCPUModel()){
+                    case 3:
+                        return "486 DX/2";
+                    case 7:
+                        return "486 DX/2-WB";
+                    case 8:
+                        return "486 DX/4";
+                    case 9:
+                        return "486 DX/4-WB";
+                    case 14:
+                        return "Am5x86-WT";
+                    case 15:
+                        return "Am5x86-WB";
+                }
+            }
+            if(getCPUFamily() == 5){
+                switch(getCPUModel()){
+                    case 0:
+                        return "K5/SSA5";
+                    case 1:
+                        return "K5";
+                    case 2:
+                        return "K5";
+                    case 3:
+                        return "K5";
+                    case 6:
+                        return "K6";
+                    case 7:
+                        return "K6";
+                    case 8:
+                        return "K6-2";
+                    case 9:
+                        return "K6-3";
+                    case 13:
+                        return "K6-2+ or K6-III+";
+                }
+            }
+            if(getCPUFamily() == 6){
+                switch(getCPUModel()){
+                    case 0:
+                        return "Athlon (250 nm)";
+                    case 1:
+                        return "Athlon (250 nm)";
+                    case 2:
+                        return "Athlon (180 nm)";
+                    case 3:
+                        return "Duron";
+                    case 4:
+                        return "Athlon (Thunderbird)";
+                    case 6:
+                        return "Athlon (Palamino)";
+                    case 7:
+                        return "Duron (Morgan)";
+                    case 8:
+                        return "Athlon (Thoroughbred)";
+                    case 10:
+                        return "Athlon (Barton)";
+                }
+            }
+            if(getCPUFamily() == 15){
+                if(getCPUExtendedFamily() == 0){
+                    switch(getCPUModel()){
+                        case 4:
+                            return "Athlon 64";
+                        case 5:
+                            return "Athlon 64 FX Opteron";
+                    }
+                }
+            }
+            throw new UnknownCPUException("Unknown AMD CPU; Family="+getCPUFamily()+", Model="+getCPUModel());
+        }
+    }
+
+    protected static class IntelInfoImpl extends CPUIDCPUInfo implements IntelCPUInfo
+    {
+        public boolean IsPentiumCompatible()
+        {
+            return getCPUFamily() >= 5;
+        }
+        public boolean IsPentiumMMXCompatible()
+        {
+            return IsPentium2Compatible() || (getCPUFamily() == 5 && (getCPUModel() ==4 || getCPUModel() == 8));
+        }
+        public boolean IsPentium2Compatible()
+        {
+            return getCPUFamily() > 6 || (getCPUFamily() == 6 && getCPUModel() >=3);
+        }
+        public boolean IsPentium3Compatible()
+        {
+            return getCPUFamily() > 6 || (getCPUFamily() == 6 && getCPUModel() >=7);
+        }
+        public boolean IsPentium4Compatible()
+        {
+            return getCPUFamily() >= 15;
+        }
+        public String getCPUModelString() throws UnknownCPUException {
+            if(getCPUFamily() == 4){
+                switch(getCPUModel()){
+                    case 0:
+                        return "486 DX-25/33";
+                    case 1:
+                        return "486 DX-50";
+                    case 2:
+                        return "486 SX";
+                    case 3:
+                        return "486 DX/2";
+                    case 4:
+                        return "486 SL";
+                    case 5:
+                        return "486 SX/2";
+                    case 7:
+                        return "486 DX/2-WB";
+                    case 8:
+                        return "486 DX/4";
+                    case 9:
+                        return "486 DX/4-WB";
+                }
+            }
+            if(getCPUFamily() == 5){
+                switch(getCPUModel()){
+                    case 0:
+                        return "Pentium 60/66 A-step";
+                    case 1:
+                        return "Pentium 60/66";
+                    case 2:
+                        return "Pentium 75 - 200";
+                    case 3:
+                        return "OverDrive PODP5V83";
+                    case 4:
+                        return "Pentium MMX";
+                    case 7:
+                        return "Mobile Pentium 75 - 200";
+                    case 8:
+                        return "Mobile Pentium MMX";
+                }
+            }
+            if(getCPUFamily() == 6){
+                switch(getCPUModel()){
+                    case 0:
+                        return "Pentium Pro A-step";
+                    case 1:
+                        return "Pentium Pro";
+                    case 3:
+                        return "Pentium II (Klamath)";
+                    case 5:
+                        return "Pentium II (Deschutes), Celeron (Covington), Mobile Pentium II (Dixon)";
+                    case 6:
+                        return "Mobile Pentium II, Celeron (Mendocino)";
+                    case 7:
+                        return "Pentium III (Katmai)";
+                    case 8:
+                        return "Pentium III (Coppermine), Celeron w/SSE";
+                    case 9:
+                        return "Mobile Pentium III";
+                    case 10:
+                        return "Pentium III Xeon (Cascades)";
+                    case 11:
+                        return "Pentium III (130 nm)";
+                }
+            }
+            if(getCPUFamily() == 7){
+                switch(getCPUModel()){
+                    //Itanium.. TODO
+                }
+            }
+            if(getCPUFamily() == 15){
+                if(getCPUExtendedFamily() == 0){
+                    switch(getCPUModel()){
+                        case 0:
+                            return "Pentium IV (180 nm)";
+                        case 1:
+                            return "Pentium IV (180 nm)";
+                        case 2:
+                            return "Pentium IV (130 nm)";
+                        case 3:
+                            return "Pentium IV (90 nm)";
+                    }
+                }
+                if(getCPUExtendedFamily() == 1){
+                    switch(getCPUModel()){
+                        //    Itanium 2.. TODO
+                    }    
+                }
+            }
+            throw new UnknownCPUException("Unknown Intel CPU; Family="+getCPUFamily()+", Model="+getCPUModel());
+        }
+    }
+
+    public static void main(String args[])
+    {
+        if(!_nativeOk){
+            System.out.println("**Failed to retrieve CPUInfo. Please verify the existence of jcpuid dll/so**");
+        }
+        System.out.println("**CPUInfo**");
+        System.out.println("CPU Vendor: " + getCPUVendorID());
+        System.out.println("CPU Family: " + getCPUFamily());
+        System.out.println("CPU Model: " + getCPUModel());
+        System.out.println("CPU Stepping: " + getCPUStepping());
+        System.out.println("CPU Flags: " + getCPUFlags());
+        
+        CPUInfo c = getInfo();
+        System.out.println(" **More CPUInfo**");
+        System.out.println(" CPU model string: " + c.getCPUModelString());
+        System.out.println(" CPU has MMX: " + c.hasMMX());
+        System.out.println(" CPU has SSE: " + c.hasSSE());
+        System.out.println(" CPU has SSE2: " + c.hasSSE2());
+        if(c instanceof IntelCPUInfo){
+            System.out.println("  **Intel-info**");
+            System.out.println("  Is pII-compatible: "+((IntelCPUInfo)c).IsPentium2Compatible());
+            System.out.println("  Is pIII-compatible: "+((IntelCPUInfo)c).IsPentium3Compatible());
+            System.out.println("  Is pIV-compatible: "+((IntelCPUInfo)c).IsPentium4Compatible());
+        }
+        if(c instanceof AMDCPUInfo){
+            System.out.println("  **AMD-info**");
+            System.out.println("  Is Athlon-compatible: "+((AMDCPUInfo)c).IsAthlonCompatible());
+        }
+        
+    }
+    
+       /**
+     * <p>Do whatever we can to load up the native library.
+     * If it can find a custom built jcpuid.dll / libjcpuid.so, it'll use that.  Otherwise
+     * it'll try to look in the classpath for the correct library (see loadFromResource).
+     * If the user specifies -Djcpuid.enable=false it'll skip all of this.</p>
+     *
+     */
+    private static final void loadNative() {
+        try{
+        String wantedProp = System.getProperty("jcpuid.enable", "true");
+        boolean wantNative = "true".equalsIgnoreCase(wantedProp);
+        if (wantNative) {
+            boolean loaded = loadFromResource();
+            if (loaded) {
+                _nativeOk = true;
+                if (_doLog)
+                    System.err.println("INFO: Native CPUID library '"+getResourceName()+"' loaded from resource");
+            } else {
+                loaded = loadGeneric();
+                if (loaded) {
+                    _nativeOk = true;
+                    if (_doLog)
+                        System.err.println("INFO: Native CPUID library '"+getLibraryMiddlePart()+"' loaded from somewhere in the path");
+                } else {
+                    _nativeOk = false;
+                    if (_doLog)
+                        System.err.println("WARN: Native CPUID library jcpuid not loaded - will not be able to read CPU information using CPUID");
+                }
+            }
+        } else {
+            if (_doLog)
+                System.err.println("INFO: Native CPUID library jcpuid not loaded - will not be able to read CPU information using CPUID");
+        }
+        }catch(Exception e){
+            if (_doLog)
+                System.err.println("INFO: Native CPUID library jcpuid not loaded, reason: '"+e.getMessage()+"' - will not be able to read CPU information using CPUID");
+        }
+    }
+    
+    /** 
+     * <p>Try loading it from an explictly built jcpuid.dll / libjcpuid.so</p>
+     *
+     * @return true if it was loaded successfully, else false
+     *
+     */
+    private static final boolean loadGeneric() {
+        try {
+            System.loadLibrary(getLibraryMiddlePart());
+            return true;
+        } catch (UnsatisfiedLinkError ule) {
+            return false;
+        }
+    }
+    
+    /**
+     * <p>Check all of the jars in the classpath for the jcpuid dll/so.
+     * This file should be stored in the resource in the same package as this class.
+     * 
+     * <p>This is a pretty ugly hack, using the general technique illustrated by the
+     * onion FEC libraries.  It works by pulling the resource, writing out the 
+     * byte stream to a temporary file, loading the native library from that file,
+     * then deleting the file.</p>
+     *
+     * @return true if it was loaded successfully, else false
+     *
+     */
+    private static final boolean loadFromResource() {
+        String resourceName = getResourceName();
+        if (resourceName == null) return false;
+        URL resource = CPUID.class.getClassLoader().getResource(resourceName);
+        
+        if (resource == null) {
+            if (_doLog)
+                System.err.println("ERROR: Resource name [" + resourceName + "] was not found");
+            return false;
+        }
+
+        File outFile = null;
+        try {
+            InputStream libStream = resource.openStream();
+            outFile = File.createTempFile("jcpuid", "lib.tmp");
+            FileOutputStream fos = new FileOutputStream(outFile);
+            byte buf[] = new byte[4096*1024];
+            while (true) {
+                int read = libStream.read(buf);
+                if (read < 0) break;
+                fos.write(buf, 0, read);
+            }
+            fos.close();
+            System.load(outFile.getAbsolutePath());//System.load requires an absolute path to the lib
+            return true;
+        } catch (UnsatisfiedLinkError ule) {
+            if (_doLog) {
+                System.err.println("ERROR: The resource " + resourceName 
+                                   + " was not a valid library for this platform");
+                ule.printStackTrace();
+            }
+            return false;
+        } catch (IOException ioe) {
+            if (_doLog) {
+                System.err.println("ERROR: Problem writing out the temporary native library data");
+                ioe.printStackTrace();
+            }
+            return false;
+        } finally {
+            if (outFile != null) {
+                outFile.deleteOnExit();
+            }
+        }
+    }
+    
+    private static final String getResourceName()
+    {
+        String pname = CPUID.class.getPackage().getName().replace('.','/');
+        return pname+"/"+getLibraryPrefix()+getLibraryMiddlePart()+"."+getLibrarySuffix();
+    }
+    
+    private static final String getLibraryPrefix()
+    {
+        boolean isWindows =System.getProperty("os.name").toLowerCase().indexOf("windows") != -1;
+        if(isWindows)
+            return "";
+        else
+            return "lib";
+    }
+    
+    private static final String getLibraryMiddlePart(){
+        boolean isWindows =(System.getProperty("os.name").toLowerCase().indexOf("windows") != -1);
+        boolean isLinux =(System.getProperty("os.name").toLowerCase().indexOf("linux") != -1);
+        boolean isFreebsd =(System.getProperty("os.name").toLowerCase().indexOf("freebsd") != -1);
+        if(isWindows)
+             return "jcpuid-x86-windows"; // The convention on Windows
+        if(isLinux)
+            return "jcpuid-x86-linux"; // The convention on linux...
+        if(isFreebsd)
+            return "jcpuid-x86-freebsd"; // The convention on freebsd...
+        throw new RuntimeException("Dont know jcpuid library name for os type '"+System.getProperty("os.name")+"'");
+    }
+    
+    private static final String getLibrarySuffix()
+    {
+        boolean isWindows =System.getProperty("os.name").toLowerCase().indexOf("windows") != -1;
+        if(isWindows)
+            return "dll";
+        else
+            return "so";
+    }
+}
diff --git a/core/java/src/freenet/support/CPUInformation/CPUInfo.java b/core/java/src/freenet/support/CPUInformation/CPUInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d7691f534641dd3fb14cabd8ced87b7b0eb2bec
--- /dev/null
+++ b/core/java/src/freenet/support/CPUInformation/CPUInfo.java
@@ -0,0 +1,45 @@
+/*
+ * Created on Jul 16, 2004
+ *
+ */
+package freenet.support.CPUInformation;
+
+/**
+ * @author Iakin
+ * An interface for classes that provide lowlevel information about CPU's
+ *
+ * free (adj.): unencumbered; not under the control of others
+ * Written by Iakin in 2004 and released into the public domain 
+ * with no warranty of any kind, either expressed or implied.  
+ * It probably won't make your computer catch on fire, or eat 
+ * your children, but it might. Use at your own risk.
+ */
+
+public interface CPUInfo
+{
+    /**
+     * @return A string indicating the vendor of the CPU.
+     */
+    public String getVendor();
+    /**
+     * @return A string detailing what type of CPU that is present in the machine. I.e. 'Pentium IV' etc.
+     * @throws UnknownCPUException If for any reson the retrieval of the requested information
+     * failed. The message encapsulated in the execption indicates the 
+     * cause of the failure.
+     */
+    public String getCPUModelString() throws UnknownCPUException;
+    
+    /**
+     * @return true iff the CPU support the MMX instruction set.
+     */
+    public boolean hasMMX();
+    /**
+     * @return true iff the CPU support the SSE instruction set.
+     */
+    public boolean hasSSE();
+    /**
+     * @return true iff the CPU support the SSE2 instruction set.
+     */
+    public boolean hasSSE2();
+    
+}
diff --git a/core/java/src/freenet/support/CPUInformation/IntelCPUInfo.java b/core/java/src/freenet/support/CPUInformation/IntelCPUInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..20f8aaf77e689e9c267218c30f4a17bccbcb2a4d
--- /dev/null
+++ b/core/java/src/freenet/support/CPUInformation/IntelCPUInfo.java
@@ -0,0 +1,40 @@
+/*
+ * Created on Jul 17, 2004
+ *
+ */
+package freenet.support.CPUInformation;
+
+/**
+ * @author Iakin
+ * An interface for classes that provide lowlevel information about Intel CPU's
+ *
+ * free (adj.): unencumbered; not under the control of others
+ * Written by Iakin in 2004 and released into the public domain 
+ * with no warranty of any kind, either expressed or implied.  
+ * It probably won't make your computer catch on fire, or eat 
+ * your children, but it might. Use at your own risk.
+ */
+public interface IntelCPUInfo extends CPUInfo {
+    /**
+     * @return true iff the CPU is at least a Pentium CPU.
+     */
+    public boolean IsPentiumCompatible();
+    /**
+     * @return true iff the CPU is at least a Pentium which implements the MMX instruction/feature set.
+     */
+    public boolean IsPentiumMMXCompatible();
+    /**
+     * @return true iff the CPU implements at least the p6 instruction set (Pentium II or better).
+     * Please note that an PentimPro CPU causes/should cause this method to return false (due to that CPU using a
+     * very early implementation of the p6 instruction set. No MMX etc.)
+     */
+    public boolean IsPentium2Compatible();
+    /**
+     * @return true iff the CPU implements at least a Pentium III level of the p6 instruction/feature set.
+     */
+    public boolean IsPentium3Compatible();
+    /**
+     * @return true iff the CPU implements at least a Pentium IV level instruction/feature set.
+     */
+    public boolean IsPentium4Compatible();
+}
diff --git a/core/java/src/freenet/support/CPUInformation/UnknownCPUException.java b/core/java/src/freenet/support/CPUInformation/UnknownCPUException.java
new file mode 100644
index 0000000000000000000000000000000000000000..f493980b258404a8f6dc03282a216f19dc6d1bc9
--- /dev/null
+++ b/core/java/src/freenet/support/CPUInformation/UnknownCPUException.java
@@ -0,0 +1,18 @@
+/*
+ * Created on Jul 16, 2004
+ */
+package freenet.support.CPUInformation;
+
+/**
+ * @author Iakin
+ *
+ */
+public class UnknownCPUException extends RuntimeException {
+    public UnknownCPUException() {
+        super();
+    }
+
+    public UnknownCPUException(String message) {
+        super(message);
+    }
+}